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

{- This module collects together stubs that connect analysis/transformations
   with the input -> output procedures -}

{-# LANGUAGE DoAndIfThenElse      #-}
{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE OverloadedStrings    #-}
{-# LANGUAGE ScopedTypeVariables  #-}
{-# LANGUAGE TupleSections        #-}
{-# LANGUAGE TypeSynonymInstances #-}

module Camfort.Functionality
  (
  -- * Datatypes
    AnnotationType(..)
  , CamfortEnv(..)
  -- * Commands
  , ast
  , countVarDecls
  , implicitNone
  , allocCheck
  , fpCheck
  , useCheck
  , arrayCheck
  -- ** Stencil Analysis
  , stencilsCheck
  , stencilsInfer
  , stencilsSynth
  -- ** Unit Analysis
  , unitsCriticals
  , unitsCheck
  , unitsDump
  , unitsInfer
  , unitsCompile
  , unitsSynth
  -- ** Invariants Analysis
  , invariantsCheck
  -- ** Refactorings
  , common
  , dead
  , equivalences
  , ddtRefactor
  , ddtInfer
  , ddtCheck
  , ddtSynth
  , ddtCompile
  -- ** Project Management
  , camfortInitialize
  ) where

import           Camfort.Analysis
import           Camfort.Analysis.Logger
import           Camfort.Analysis.ModFile (readParseSrcFile,  MFCompiler, getModFiles, genModFiles
                                          , readParseSrcDir, readParseSrcDirP, simpleCompiler)
import           Camfort.Analysis.Simple
import           Camfort.Helpers (FileOrDir, Filename)
import           Camfort.Input
import qualified Camfort.Specification.DerivedDataType as DDT
import qualified Camfort.Specification.Hoare as Hoare
import qualified Camfort.Specification.Stencils as Stencils
import           Camfort.Specification.Stencils.Analysis (compileStencils)
import qualified Camfort.Specification.Units as LU
import           Camfort.Specification.Units.Analysis (compileUnits)
import           Camfort.Specification.Units.Analysis.Consistent (checkUnits)
import           Camfort.Specification.Units.Analysis.Criticals (inferCriticalVariables)
import           Camfort.Specification.Units.Analysis.Infer (InferenceResult(..), InferenceReport(..), inferUnits)
import           Camfort.Specification.Units.Annotation (unitInfo)
import           Camfort.Specification.Units.ModFile (dumpModFileCompiledUnits)
import           Camfort.Specification.Units.Monad (runUnitAnalysis, unitOpts0)
import           Camfort.Specification.Units.MonadTypes (LiteralsOpt, UnitAnalysis, UnitEnv (..), UnitOpts (..))
import           Camfort.Transformation.CommonBlockElim
import           Camfort.Transformation.DeadCode
import           Camfort.Transformation.EquivalenceElim
import           Control.DeepSeq
import           Control.Monad
import           Control.Monad.IO.Class
import qualified Data.ByteString.Lazy as LB
import           Data.Char (toLower)
import           Data.List (intersperse)
import           Data.Maybe (fromMaybe)
import qualified Language.Fortran.Analysis as FA
import qualified Language.Fortran.Analysis.ModGraph as FM
import qualified Language.Fortran.Analysis.Renaming as FA
import           Language.Fortran.ParserMonad (FortranVersion(..))
import qualified Language.Fortran.Util.ModFile as FM
import           Pipes
import qualified Pipes.Prelude as P
import           Prelude hiding (mod)
import           System.Directory
import           System.Directory (doesDirectoryExist, createDirectoryIfMissing, getCurrentDirectory)
import           System.FilePath (takeDirectory, (</>), takeExtension, replaceExtension)
import           System.IO
import           Text.PrettyPrint.GenericPretty (pp)

data AnnotationType = ATDefault | Doxygen | Ford


-- | Retrieve the marker character compatible with the given
-- type of annotation.
markerChar :: AnnotationType -> Char
markerChar :: AnnotationType -> Char
markerChar AnnotationType
Doxygen   = Char
'<'
markerChar AnnotationType
Ford      = Char
'!'
markerChar AnnotationType
ATDefault = Char
'='

data CamfortEnv =
  CamfortEnv
  { CamfortEnv -> FileOrDir
ceInputSources   :: FileOrDir
  , CamfortEnv -> Maybe FileOrDir
ceIncludeDir     :: Maybe FileOrDir
  , CamfortEnv -> [FileOrDir]
ceExcludeFiles   :: [Filename]
  , CamfortEnv -> LogLevel
ceLogLevel       :: LogLevel
  , CamfortEnv -> Bool
ceSourceSnippets :: Bool
  , CamfortEnv -> Maybe FortranVersion
ceFortranVersion :: Maybe FortranVersion
  }

--------------------------------------------------------------------------------
-- *  Running Functionality

runWithOutput
  :: (Describe e, Describe w)
  => String
  -- ^ Functionality desription
  -> AnalysisProgram e w IO a b
  -- ^ Analysis program
  -> (FileOrDir -> FilePath -> AnalysisRunner e w IO a b r)
  -- ^ Analysis runner
  -> MFCompiler i IO
  -- ^ Mod file compiler
  -> i
  -- ^ Mod file input
  -> FilePath
  -> CamfortEnv
  -> IO r
runWithOutput :: FileOrDir
-> AnalysisProgram e w IO a b
-> (FileOrDir -> FileOrDir -> AnalysisRunner e w IO a b r)
-> MFCompiler i IO
-> i
-> FileOrDir
-> CamfortEnv
-> IO r
runWithOutput FileOrDir
description AnalysisProgram e w IO a b
program FileOrDir -> FileOrDir -> AnalysisRunner e w IO a b r
runner MFCompiler i IO
mfCompiler i
mfInput FileOrDir
outSrc CamfortEnv
env =
  let runner' :: AnalysisRunner e w IO a b r
runner' = FileOrDir -> FileOrDir -> AnalysisRunner e w IO a b r
runner (CamfortEnv -> FileOrDir
ceInputSources CamfortEnv
env) FileOrDir
outSrc
  in FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunner e w IO a b r
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO r
forall e w a b r i.
(Describe e, Describe w) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunner e w IO a b r
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO r
runFunctionality FileOrDir
description AnalysisProgram e w IO a b
program AnalysisRunner e w IO a b r
runner' MFCompiler i IO
mfCompiler i
mfInput CamfortEnv
env


runFunctionality
  :: (Describe e, Describe w)
  => String
  -- ^ Functionality desription
  -> AnalysisProgram e w IO a b
  -- ^ Analysis program
  -> AnalysisRunner e w IO a b r
  -- ^ Analysis runner
  -> MFCompiler i IO
  -- ^ Mod file compiler
  -> i
  -- ^ Mod file input
  -> CamfortEnv
  -> IO r
runFunctionality :: FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunner e w IO a b r
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO r
runFunctionality FileOrDir
description AnalysisProgram e w IO a b
program AnalysisRunner e w IO a b r
runner MFCompiler i IO
_ i
_ CamfortEnv
env = do
  FileOrDir -> IO ()
putStrLn (FileOrDir -> IO ()) -> FileOrDir -> IO ()
forall a b. (a -> b) -> a -> b
$ FileOrDir
description FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
" '" FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ CamfortEnv -> FileOrDir
ceInputSources CamfortEnv
env FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
"'"
  FileOrDir
incDir' <- IO FileOrDir
-> (FileOrDir -> IO FileOrDir) -> Maybe FileOrDir -> IO FileOrDir
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO FileOrDir
getCurrentDirectory FileOrDir -> IO FileOrDir
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CamfortEnv -> Maybe FileOrDir
ceIncludeDir CamfortEnv
env)
  Bool
isDir <- FileOrDir -> IO Bool
doesDirectoryExist FileOrDir
incDir'
  let incDir :: FileOrDir
incDir | Bool
isDir     = FileOrDir
incDir'
             | Bool
otherwise = FileOrDir -> FileOrDir
takeDirectory FileOrDir
incDir'
  -- Previously...
--modFiles <- genModFiles mfCompiler mfInput incDir (ceExcludeFiles env)
  -- ...instead for now, just get the mod files

  ModFiles
modFiles <- FileOrDir -> IO ModFiles
getModFiles FileOrDir
incDir
  [(ProgramFile A, SourceText)]
pfsTexts <- Maybe FortranVersion
-> ModFiles
-> FileOrDir
-> [FileOrDir]
-> IO [(ProgramFile A, SourceText)]
readParseSrcDir (CamfortEnv -> Maybe FortranVersion
ceFortranVersion CamfortEnv
env) ModFiles
modFiles (CamfortEnv -> FileOrDir
ceInputSources CamfortEnv
env) (CamfortEnv -> [FileOrDir]
ceExcludeFiles CamfortEnv
env)
  AnalysisRunner e w IO a b r
runner AnalysisProgram e w IO a b
program (Bool -> LogOutput IO
forall (m :: * -> *). MonadIO m => Bool -> LogOutput m
logOutputStd Bool
True) (CamfortEnv -> LogLevel
ceLogLevel CamfortEnv
env) (CamfortEnv -> Bool
ceSourceSnippets CamfortEnv
env) ModFiles
modFiles [(ProgramFile A, SourceText)]
pfsTexts

runFunctionalityP
  :: (Describe e, Describe w, ExitCodeOfReport b)
  => String
  -- ^ Functionality desription
  -> AnalysisProgram e w IO a b
  -- ^ Analysis program
  -> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
  -- ^ Analysis runner
  -> MFCompiler i IO
  -- ^ Mod file compiler
  -> i
  -- ^ Mod file input
  -> CamfortEnv
  -> IO Int
runFunctionalityP :: FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO Int
runFunctionalityP FileOrDir
description AnalysisProgram e w IO a b
program AnalysisRunnerP e w IO a b (AnalysisReport e w b)
runner MFCompiler i IO
_ i
_ CamfortEnv
env = do
  FileOrDir -> IO ()
putStrLn (FileOrDir -> IO ()) -> FileOrDir -> IO ()
forall a b. (a -> b) -> a -> b
$ FileOrDir
description FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
" '" FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ CamfortEnv -> FileOrDir
ceInputSources CamfortEnv
env FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
"'"
  FileOrDir
incDir' <- IO FileOrDir
-> (FileOrDir -> IO FileOrDir) -> Maybe FileOrDir -> IO FileOrDir
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO FileOrDir
getCurrentDirectory FileOrDir -> IO FileOrDir
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CamfortEnv -> Maybe FileOrDir
ceIncludeDir CamfortEnv
env)
  Bool
isDir <- FileOrDir -> IO Bool
doesDirectoryExist FileOrDir
incDir'
  let incDir :: FileOrDir
incDir | Bool
isDir     = FileOrDir
incDir'
             | Bool
otherwise = FileOrDir -> FileOrDir
takeDirectory FileOrDir
incDir'
  -- Previously...
--modFiles <- genModFiles mfCompiler mfInput incDir (ceExcludeFiles env)
  -- ...instead for now, just get the mod files

  ModFiles
modFiles <- FileOrDir -> IO ModFiles
getModFiles FileOrDir
incDir

  [AnalysisReport e w b]
reports <- Producer (AnalysisReport e w b) IO () -> IO [AnalysisReport e w b]
forall (m :: * -> *) a. Monad m => Producer a m () -> m [a]
P.toListM (Producer (AnalysisReport e w b) IO ()
 -> IO [AnalysisReport e w b])
-> Producer (AnalysisReport e w b) IO ()
-> IO [AnalysisReport e w b]
forall a b. (a -> b) -> a -> b
$
    Maybe FortranVersion
-> ModFiles
-> FileOrDir
-> [FileOrDir]
-> Producer' (ProgramFile A, SourceText) IO ()
forall (m :: * -> *).
MonadIO m =>
Maybe FortranVersion
-> ModFiles
-> FileOrDir
-> [FileOrDir]
-> Producer' (ProgramFile A, SourceText) m ()
readParseSrcDirP (CamfortEnv -> Maybe FortranVersion
ceFortranVersion CamfortEnv
env) ModFiles
modFiles (CamfortEnv -> FileOrDir
ceInputSources CamfortEnv
env) (CamfortEnv -> [FileOrDir]
ceExcludeFiles CamfortEnv
env) Proxy X () () (ProgramFile A, SourceText) IO ()
-> Proxy
     () (ProgramFile A, SourceText) () (AnalysisReport e w b) IO ()
-> Producer (AnalysisReport e w b) IO ()
forall (m :: * -> *) a' a b r c' c.
Functor m =>
Proxy a' a () b m r -> Proxy () b c' c m r -> Proxy a' a c' c m r
>->
    AnalysisRunnerP e w IO a b (AnalysisReport e w b)
runner AnalysisProgram e w IO a b
program (Bool -> LogOutput IO
forall (m :: * -> *). MonadIO m => Bool -> LogOutput m
logOutputStd Bool
True) (CamfortEnv -> LogLevel
ceLogLevel CamfortEnv
env) (CamfortEnv -> Bool
ceSourceSnippets CamfortEnv
env) ModFiles
modFiles
  Int -> IO Int
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> IO Int)
-> ([AnalysisReport e w b] -> Int)
-> [AnalysisReport e w b]
-> IO Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [AnalysisReport e w b] -> Int
forall a. ExitCodeOfReport a => [a] -> Int
exitCodeOfSet ([AnalysisReport e w b] -> IO Int)
-> [AnalysisReport e w b] -> IO Int
forall a b. (a -> b) -> a -> b
$ [AnalysisReport e w b]
reports

--------------------------------------------------------------------------------
-- * Wrappers on all of the features

ast :: CamfortEnv -> IO ()
ast :: CamfortEnv -> IO ()
ast CamfortEnv
env = do
    FileOrDir
incDir' <- IO FileOrDir
-> (FileOrDir -> IO FileOrDir) -> Maybe FileOrDir -> IO FileOrDir
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO FileOrDir
getCurrentDirectory FileOrDir -> IO FileOrDir
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CamfortEnv -> Maybe FileOrDir
ceIncludeDir CamfortEnv
env)
    ModFiles
modFiles <- FileOrDir -> IO ModFiles
getModFiles FileOrDir
incDir'
    [(ProgramFile A, SourceText)]
xs <- Maybe FortranVersion
-> ModFiles
-> FileOrDir
-> [FileOrDir]
-> IO [(ProgramFile A, SourceText)]
readParseSrcDir (CamfortEnv -> Maybe FortranVersion
ceFortranVersion CamfortEnv
env) ModFiles
modFiles (CamfortEnv -> FileOrDir
ceInputSources CamfortEnv
env) (CamfortEnv -> [FileOrDir]
ceExcludeFiles CamfortEnv
env)
    [ProgramFile A] -> IO ()
forall a. Show a => a -> IO ()
print ([ProgramFile A] -> IO ())
-> ([(ProgramFile A, SourceText)] -> [ProgramFile A])
-> [(ProgramFile A, SourceText)]
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((ProgramFile A, SourceText) -> ProgramFile A)
-> [(ProgramFile A, SourceText)] -> [ProgramFile A]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ProgramFile A, SourceText) -> ProgramFile A
forall a b. (a, b) -> a
fst ([(ProgramFile A, SourceText)] -> IO ())
-> [(ProgramFile A, SourceText)] -> IO ()
forall a b. (a -> b) -> a -> b
$ [(ProgramFile A, SourceText)]
xs


countVarDecls :: CamfortEnv -> IO Int
countVarDecls :: CamfortEnv -> IO Int
countVarDecls =
  FileOrDir
-> AnalysisProgram () () IO (ProgramFile A) VarCountReport
-> AnalysisRunnerP
     ()
     ()
     IO
     (ProgramFile A)
     VarCountReport
     (AnalysisReport () () VarCountReport)
-> MFCompiler () IO
-> ()
-> CamfortEnv
-> IO Int
forall e w b a i.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO Int
runFunctionalityP
  FileOrDir
"Counting variable declarations in"
  (PureAnalysis () () VarCountReport
-> AnalysisT () () IO VarCountReport
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (PureAnalysis () () VarCountReport
 -> AnalysisT () () IO VarCountReport)
-> (ProgramFile A -> PureAnalysis () () VarCountReport)
-> AnalysisProgram () () IO (ProgramFile A) VarCountReport
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramFile A -> PureAnalysis () () VarCountReport
forall a.
Data a =>
ProgramFile a -> PureAnalysis () () VarCountReport
countVariableDeclarations)
  (Text
-> AnalysisRunnerP
     ()
     ()
     IO
     (ProgramFile A)
     VarCountReport
     (AnalysisReport () () VarCountReport)
forall (m :: * -> *) r w e.
(MonadIO m, Describe r, ExitCodeOfReport r, Describe w, Describe e,
 NFData e, NFData w, NFData r) =>
Text
-> AnalysisRunnerP e w m (ProgramFile A) r (AnalysisReport e w r)
describePerFileAnalysisP Text
"count variable declarations")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
simpleCompiler ()

dead :: FileOrDir -> CamfortEnv -> IO Int
dead :: FileOrDir -> CamfortEnv -> IO Int
dead =
  FileOrDir
-> AnalysisProgram
     X X IO [ProgramFile A] ((), [Either X (ProgramFile A)])
-> (FileOrDir
    -> FileOrDir
    -> AnalysisRunner
         X X IO [ProgramFile A] ((), [Either X (ProgramFile A)]) Int)
-> MFCompiler () IO
-> ()
-> FileOrDir
-> CamfortEnv
-> IO Int
forall e w a b r i.
(Describe e, Describe w) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> (FileOrDir -> FileOrDir -> AnalysisRunner e w IO a b r)
-> MFCompiler i IO
-> i
-> FileOrDir
-> CamfortEnv
-> IO r
runWithOutput
  FileOrDir
"Eliminating dead code in"
  ((PureAnalysis X X ((), [Either X (ProgramFile A)])
 -> AnalysisT X X IO ((), [Either X (ProgramFile A)]))
-> ([ProgramFile A]
    -> PureAnalysis X X ((), [Either X (ProgramFile A)]))
-> AnalysisProgram
     X X IO [ProgramFile A] ((), [Either X (ProgramFile A)])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap PureAnalysis X X ((), [Either X (ProgramFile A)])
-> AnalysisT X X IO ((), [Either X (ProgramFile A)])
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (([ProgramFile A]
  -> PureAnalysis X X ((), [Either X (ProgramFile A)]))
 -> AnalysisProgram
      X X IO [ProgramFile A] ((), [Either X (ProgramFile A)]))
-> (AnalysisProgram X X Identity (ProgramFile A) (ProgramFile A)
    -> [ProgramFile A]
    -> PureAnalysis X X ((), [Either X (ProgramFile A)]))
-> AnalysisProgram X X Identity (ProgramFile A) (ProgramFile A)
-> AnalysisProgram
     X X IO [ProgramFile A] ((), [Either X (ProgramFile A)])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AnalysisProgram X X Identity (ProgramFile A) (ProgramFile A)
-> [ProgramFile A]
-> PureAnalysis X X ((), [Either X (ProgramFile A)])
forall (m :: * -> *) e w.
Monad m =>
AnalysisProgram e w m (ProgramFile A) (ProgramFile A)
-> AnalysisProgram
     e w m [ProgramFile A] ((), [Either e (ProgramFile A)])
perFileRefactoring (AnalysisProgram X X Identity (ProgramFile A) (ProgramFile A)
 -> AnalysisProgram
      X X IO [ProgramFile A] ((), [Either X (ProgramFile A)]))
-> AnalysisProgram X X Identity (ProgramFile A) (ProgramFile A)
-> AnalysisProgram
     X X IO [ProgramFile A] ((), [Either X (ProgramFile A)])
forall a b. (a -> b) -> a -> b
$ Bool
-> AnalysisProgram X X Identity (ProgramFile A) (ProgramFile A)
deadCode Bool
False)
  (Text
-> FileOrDir
-> FileOrDir
-> AnalysisRunner
     X X IO [ProgramFile A] ((), [Either X (ProgramFile A)]) Int
forall e e' w r.
(Describe e, Describe e', Describe w, Describe r,
 ExitCodeOfReport r) =>
Text
-> FileOrDir
-> FileOrDir
-> AnalysisRunner
     e w IO [ProgramFile A] (r, [Either e' (ProgramFile A)]) Int
doRefactor Text
"dead code elimination")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
simpleCompiler ()


common :: FileOrDir -> CamfortEnv -> IO Int
common :: FileOrDir -> CamfortEnv -> IO Int
common FileOrDir
outSrc =
  FileOrDir
-> AnalysisProgram
     X X IO [ProgramFile A] ([ProgramFile A], [ProgramFile A])
-> (FileOrDir
    -> FileOrDir
    -> AnalysisRunner
         X X IO [ProgramFile A] ([ProgramFile A], [ProgramFile A]) Int)
-> MFCompiler () IO
-> ()
-> FileOrDir
-> CamfortEnv
-> IO Int
forall e w a b r i.
(Describe e, Describe w) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> (FileOrDir -> FileOrDir -> AnalysisRunner e w IO a b r)
-> MFCompiler i IO
-> i
-> FileOrDir
-> CamfortEnv
-> IO r
runWithOutput
  FileOrDir
"Refactoring common blocks in"
  (PureAnalysis X X ([ProgramFile A], [ProgramFile A])
-> AnalysisT X X IO ([ProgramFile A], [ProgramFile A])
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (PureAnalysis X X ([ProgramFile A], [ProgramFile A])
 -> AnalysisT X X IO ([ProgramFile A], [ProgramFile A]))
-> ([ProgramFile A]
    -> PureAnalysis X X ([ProgramFile A], [ProgramFile A]))
-> AnalysisProgram
     X X IO [ProgramFile A] ([ProgramFile A], [ProgramFile A])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FileOrDir
-> [ProgramFile A]
-> PureAnalysis X X ([ProgramFile A], [ProgramFile A])
commonElimToModules (FileOrDir -> FileOrDir
takeDirectory FileOrDir
outSrc FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
"/"))
  (Text
-> FileOrDir
-> FileOrDir
-> AnalysisRunner
     X X IO [ProgramFile A] ([ProgramFile A], [ProgramFile A]) Int
forall e w.
(Describe e, Describe w) =>
Text
-> FileOrDir
-> FileOrDir
-> AnalysisRunner
     e w IO [ProgramFile A] ([ProgramFile A], [ProgramFile A]) Int
doRefactorAndCreate Text
"common block refactoring")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
simpleCompiler ()
  FileOrDir
outSrc


equivalences :: FileOrDir -> CamfortEnv -> IO Int
equivalences :: FileOrDir -> CamfortEnv -> IO Int
equivalences =
  FileOrDir
-> AnalysisProgram
     X X IO [ProgramFile A] ((), [Either X (ProgramFile A)])
-> (FileOrDir
    -> FileOrDir
    -> AnalysisRunner
         X X IO [ProgramFile A] ((), [Either X (ProgramFile A)]) Int)
-> MFCompiler () IO
-> ()
-> FileOrDir
-> CamfortEnv
-> IO Int
forall e w a b r i.
(Describe e, Describe w) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> (FileOrDir -> FileOrDir -> AnalysisRunner e w IO a b r)
-> MFCompiler i IO
-> i
-> FileOrDir
-> CamfortEnv
-> IO r
runWithOutput
  FileOrDir
"Refactoring equivalences blocks in"
  ((PureAnalysis X X ((), [Either X (ProgramFile A)])
 -> AnalysisT X X IO ((), [Either X (ProgramFile A)]))
-> ([ProgramFile A]
    -> PureAnalysis X X ((), [Either X (ProgramFile A)]))
-> AnalysisProgram
     X X IO [ProgramFile A] ((), [Either X (ProgramFile A)])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap PureAnalysis X X ((), [Either X (ProgramFile A)])
-> AnalysisT X X IO ((), [Either X (ProgramFile A)])
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (([ProgramFile A]
  -> PureAnalysis X X ((), [Either X (ProgramFile A)]))
 -> AnalysisProgram
      X X IO [ProgramFile A] ((), [Either X (ProgramFile A)]))
-> (AnalysisProgram X X Identity (ProgramFile A) (ProgramFile A)
    -> [ProgramFile A]
    -> PureAnalysis X X ((), [Either X (ProgramFile A)]))
-> AnalysisProgram X X Identity (ProgramFile A) (ProgramFile A)
-> AnalysisProgram
     X X IO [ProgramFile A] ((), [Either X (ProgramFile A)])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AnalysisProgram X X Identity (ProgramFile A) (ProgramFile A)
-> [ProgramFile A]
-> PureAnalysis X X ((), [Either X (ProgramFile A)])
forall (m :: * -> *) e w.
Monad m =>
AnalysisProgram e w m (ProgramFile A) (ProgramFile A)
-> AnalysisProgram
     e w m [ProgramFile A] ((), [Either e (ProgramFile A)])
perFileRefactoring (AnalysisProgram X X Identity (ProgramFile A) (ProgramFile A)
 -> AnalysisProgram
      X X IO [ProgramFile A] ((), [Either X (ProgramFile A)]))
-> AnalysisProgram X X Identity (ProgramFile A) (ProgramFile A)
-> AnalysisProgram
     X X IO [ProgramFile A] ((), [Either X (ProgramFile A)])
forall a b. (a -> b) -> a -> b
$ AnalysisProgram X X Identity (ProgramFile A) (ProgramFile A)
refactorEquivalences)
  (Text
-> FileOrDir
-> FileOrDir
-> AnalysisRunner
     X X IO [ProgramFile A] ((), [Either X (ProgramFile A)]) Int
forall e e' w r.
(Describe e, Describe e', Describe w, Describe r,
 ExitCodeOfReport r) =>
Text
-> FileOrDir
-> FileOrDir
-> AnalysisRunner
     e w IO [ProgramFile A] (r, [Either e' (ProgramFile A)]) Int
doRefactor Text
"equivalence block refactoring")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
simpleCompiler ()

implicitNone :: Bool -> CamfortEnv -> IO Int
implicitNone :: Bool -> CamfortEnv -> IO Int
implicitNone Bool
allPU =
  FileOrDir
-> AnalysisProgram
     FileOrDir () IO (ProgramFile A) ImplicitNoneReport
-> AnalysisRunnerP
     FileOrDir
     ()
     IO
     (ProgramFile A)
     ImplicitNoneReport
     (AnalysisReport FileOrDir () ImplicitNoneReport)
-> MFCompiler () IO
-> ()
-> CamfortEnv
-> IO Int
forall e w b a i.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO Int
runFunctionalityP
  FileOrDir
"Checking 'implicit none' completeness"
  (PureAnalysis FileOrDir () ImplicitNoneReport
-> AnalysisT FileOrDir () IO ImplicitNoneReport
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (PureAnalysis FileOrDir () ImplicitNoneReport
 -> AnalysisT FileOrDir () IO ImplicitNoneReport)
-> (ProgramFile A -> PureAnalysis FileOrDir () ImplicitNoneReport)
-> AnalysisProgram
     FileOrDir () IO (ProgramFile A) ImplicitNoneReport
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool
-> ProgramFile A -> PureAnalysis FileOrDir () ImplicitNoneReport
forall a.
Data a =>
Bool
-> ProgramFile a -> PureAnalysis FileOrDir () ImplicitNoneReport
checkImplicitNone Bool
allPU))
  (Text
-> AnalysisRunnerP
     FileOrDir
     ()
     IO
     (ProgramFile A)
     ImplicitNoneReport
     (AnalysisReport FileOrDir () ImplicitNoneReport)
forall (m :: * -> *) r w e.
(MonadIO m, Describe r, ExitCodeOfReport r, Describe w, Describe e,
 NFData e, NFData w, NFData r) =>
Text
-> AnalysisRunnerP e w m (ProgramFile A) r (AnalysisReport e w r)
describePerFileAnalysisP Text
"check 'implicit none'")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
simpleCompiler ()

allocCheck :: CamfortEnv -> IO Int
allocCheck :: CamfortEnv -> IO Int
allocCheck =
  FileOrDir
-> AnalysisProgram FileOrDir () IO (ProgramFile A) CheckAllocReport
-> AnalysisRunnerP
     FileOrDir
     ()
     IO
     (ProgramFile A)
     CheckAllocReport
     (AnalysisReport FileOrDir () CheckAllocReport)
-> MFCompiler () IO
-> ()
-> CamfortEnv
-> IO Int
forall e w b a i.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO Int
runFunctionalityP
  FileOrDir
"Checking allocate / deallocate usage"
  (PureAnalysis FileOrDir () CheckAllocReport
-> AnalysisT FileOrDir () IO CheckAllocReport
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (PureAnalysis FileOrDir () CheckAllocReport
 -> AnalysisT FileOrDir () IO CheckAllocReport)
-> (ProgramFile A -> PureAnalysis FileOrDir () CheckAllocReport)
-> AnalysisProgram FileOrDir () IO (ProgramFile A) CheckAllocReport
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramFile A -> PureAnalysis FileOrDir () CheckAllocReport
forall a.
Data a =>
ProgramFile a -> PureAnalysis FileOrDir () CheckAllocReport
checkAllocateStatements)
  (Text
-> AnalysisRunnerP
     FileOrDir
     ()
     IO
     (ProgramFile A)
     CheckAllocReport
     (AnalysisReport FileOrDir () CheckAllocReport)
forall (m :: * -> *) r w e.
(MonadIO m, Describe r, ExitCodeOfReport r, Describe w, Describe e,
 NFData e, NFData w, NFData r) =>
Text
-> AnalysisRunnerP e w m (ProgramFile A) r (AnalysisReport e w r)
describePerFileAnalysisP Text
"check allocate / deallocate")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
simpleCompiler ()

fpCheck :: CamfortEnv -> IO Int
fpCheck :: CamfortEnv -> IO Int
fpCheck =
  FileOrDir
-> AnalysisProgram FileOrDir () IO (ProgramFile A) CheckFPReport
-> AnalysisRunnerP
     FileOrDir
     ()
     IO
     (ProgramFile A)
     CheckFPReport
     (AnalysisReport FileOrDir () CheckFPReport)
-> MFCompiler () IO
-> ()
-> CamfortEnv
-> IO Int
forall e w b a i.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO Int
runFunctionalityP
  FileOrDir
"Checking usage of floating point"
  (PureAnalysis FileOrDir () CheckFPReport
-> AnalysisT FileOrDir () IO CheckFPReport
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (PureAnalysis FileOrDir () CheckFPReport
 -> AnalysisT FileOrDir () IO CheckFPReport)
-> (ProgramFile A -> PureAnalysis FileOrDir () CheckFPReport)
-> AnalysisProgram FileOrDir () IO (ProgramFile A) CheckFPReport
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramFile A -> PureAnalysis FileOrDir () CheckFPReport
forall a.
Data a =>
ProgramFile a -> PureAnalysis FileOrDir () CheckFPReport
checkFloatingPointUse)
  (Text
-> AnalysisRunnerP
     FileOrDir
     ()
     IO
     (ProgramFile A)
     CheckFPReport
     (AnalysisReport FileOrDir () CheckFPReport)
forall (m :: * -> *) r w e.
(MonadIO m, Describe r, ExitCodeOfReport r, Describe w, Describe e,
 NFData e, NFData w, NFData r) =>
Text
-> AnalysisRunnerP e w m (ProgramFile A) r (AnalysisReport e w r)
describePerFileAnalysisP Text
"check floating point")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
simpleCompiler ()

useCheck :: CamfortEnv -> IO Int
useCheck :: CamfortEnv -> IO Int
useCheck =
  FileOrDir
-> AnalysisProgram FileOrDir () IO (ProgramFile A) CheckUseReport
-> AnalysisRunnerP
     FileOrDir
     ()
     IO
     (ProgramFile A)
     CheckUseReport
     (AnalysisReport FileOrDir () CheckUseReport)
-> MFCompiler () IO
-> ()
-> CamfortEnv
-> IO Int
forall e w b a i.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO Int
runFunctionalityP
  FileOrDir
"Checking usage of USE statements"
  (PureAnalysis FileOrDir () CheckUseReport
-> AnalysisT FileOrDir () IO CheckUseReport
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (PureAnalysis FileOrDir () CheckUseReport
 -> AnalysisT FileOrDir () IO CheckUseReport)
-> (ProgramFile A -> PureAnalysis FileOrDir () CheckUseReport)
-> AnalysisProgram FileOrDir () IO (ProgramFile A) CheckUseReport
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramFile A -> PureAnalysis FileOrDir () CheckUseReport
forall a.
Data a =>
ProgramFile a -> PureAnalysis FileOrDir () CheckUseReport
checkModuleUse)
  (Text
-> AnalysisRunnerP
     FileOrDir
     ()
     IO
     (ProgramFile A)
     CheckUseReport
     (AnalysisReport FileOrDir () CheckUseReport)
forall (m :: * -> *) r w e.
(MonadIO m, Describe r, ExitCodeOfReport r, Describe w, Describe e,
 NFData e, NFData w, NFData r) =>
Text
-> AnalysisRunnerP e w m (ProgramFile A) r (AnalysisReport e w r)
describePerFileAnalysisP Text
"check module USE")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
simpleCompiler ()

arrayCheck :: CamfortEnv -> IO Int
arrayCheck :: CamfortEnv -> IO Int
arrayCheck =
  FileOrDir
-> AnalysisProgram FileOrDir () IO (ProgramFile A) CheckArrayReport
-> AnalysisRunnerP
     FileOrDir
     ()
     IO
     (ProgramFile A)
     CheckArrayReport
     (AnalysisReport FileOrDir () CheckArrayReport)
-> MFCompiler () IO
-> ()
-> CamfortEnv
-> IO Int
forall e w b a i.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO Int
runFunctionalityP
  FileOrDir
"Checking array usage"
  (PureAnalysis FileOrDir () CheckArrayReport
-> AnalysisT FileOrDir () IO CheckArrayReport
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (PureAnalysis FileOrDir () CheckArrayReport
 -> AnalysisT FileOrDir () IO CheckArrayReport)
-> (ProgramFile A -> PureAnalysis FileOrDir () CheckArrayReport)
-> AnalysisProgram FileOrDir () IO (ProgramFile A) CheckArrayReport
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramFile A -> PureAnalysis FileOrDir () CheckArrayReport
forall a.
Data a =>
ProgramFile a -> PureAnalysis FileOrDir () CheckArrayReport
checkArrayUse)
  (Text
-> AnalysisRunnerP
     FileOrDir
     ()
     IO
     (ProgramFile A)
     CheckArrayReport
     (AnalysisReport FileOrDir () CheckArrayReport)
forall (m :: * -> *) r w e.
(MonadIO m, Describe r, ExitCodeOfReport r, Describe w, Describe e,
 NFData e, NFData w, NFData r) =>
Text
-> AnalysisRunnerP e w m (ProgramFile A) r (AnalysisReport e w r)
describePerFileAnalysisP Text
"check array usage")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
simpleCompiler ()

ddtRefactor :: FileOrDir -> CamfortEnv -> IO Int
ddtRefactor :: FileOrDir -> CamfortEnv -> IO Int
ddtRefactor =
  FileOrDir
-> AnalysisProgram
     FileOrDir
     ()
     IO
     [ProgramFile A]
     (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
-> (FileOrDir
    -> FileOrDir
    -> AnalysisRunner
         FileOrDir
         ()
         IO
         [ProgramFile A]
         (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
         Int)
-> MFCompiler () IO
-> ()
-> FileOrDir
-> CamfortEnv
-> IO Int
forall e w a b r i.
(Describe e, Describe w) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> (FileOrDir -> FileOrDir -> AnalysisRunner e w IO a b r)
-> MFCompiler i IO
-> i
-> FileOrDir
-> CamfortEnv
-> IO r
runWithOutput
  FileOrDir
"Refactoring derived datatypes"
  (PureAnalysis
  FileOrDir
  ()
  (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
-> AnalysisT
     FileOrDir
     ()
     IO
     (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (PureAnalysis
   FileOrDir
   ()
   (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
 -> AnalysisT
      FileOrDir
      ()
      IO
      (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)]))
-> ([ProgramFile A]
    -> PureAnalysis
         FileOrDir
         ()
         (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)]))
-> AnalysisProgram
     FileOrDir
     ()
     IO
     [ProgramFile A]
     (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ProgramFile A]
-> PureAnalysis
     FileOrDir
     ()
     (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
DDT.refactor)
  (Text
-> FileOrDir
-> FileOrDir
-> AnalysisRunner
     FileOrDir
     ()
     IO
     [ProgramFile A]
     (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
     Int
forall e e' w r.
(Describe e, Describe e', Describe w, Describe r,
 ExitCodeOfReport r) =>
Text
-> FileOrDir
-> FileOrDir
-> AnalysisRunner
     e w IO [ProgramFile A] (r, [Either e' (ProgramFile A)]) Int
doRefactor Text
"infer derived data types")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
simpleCompiler ()

ddtSynth :: AnnotationType -> FileOrDir -> CamfortEnv -> IO Int
ddtSynth :: AnnotationType -> FileOrDir -> CamfortEnv -> IO Int
ddtSynth AnnotationType
annType =
  FileOrDir
-> AnalysisProgram
     FileOrDir
     ()
     IO
     [ProgramFile A]
     (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
-> (FileOrDir
    -> FileOrDir
    -> AnalysisRunner
         FileOrDir
         ()
         IO
         [ProgramFile A]
         (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
         Int)
-> MFCompiler () IO
-> ()
-> FileOrDir
-> CamfortEnv
-> IO Int
forall e w a b r i.
(Describe e, Describe w) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> (FileOrDir -> FileOrDir -> AnalysisRunner e w IO a b r)
-> MFCompiler i IO
-> i
-> FileOrDir
-> CamfortEnv
-> IO r
runWithOutput
  FileOrDir
"Synthesising derived datatypes"
  (PureAnalysis
  FileOrDir
  ()
  (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
-> AnalysisT
     FileOrDir
     ()
     IO
     (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (PureAnalysis
   FileOrDir
   ()
   (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
 -> AnalysisT
      FileOrDir
      ()
      IO
      (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)]))
-> ([ProgramFile A]
    -> PureAnalysis
         FileOrDir
         ()
         (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)]))
-> AnalysisProgram
     FileOrDir
     ()
     IO
     [ProgramFile A]
     (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char
-> [ProgramFile A]
-> PureAnalysis
     FileOrDir
     ()
     (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
DDT.synth (AnnotationType -> Char
markerChar AnnotationType
annType))
  (Text
-> FileOrDir
-> FileOrDir
-> AnalysisRunner
     FileOrDir
     ()
     IO
     [ProgramFile A]
     (DerivedDataTypeReport, [Either FileOrDir (ProgramFile A)])
     Int
forall e e' w r.
(Describe e, Describe e', Describe w, Describe r,
 ExitCodeOfReport r) =>
Text
-> FileOrDir
-> FileOrDir
-> AnalysisRunner
     e w IO [ProgramFile A] (r, [Either e' (ProgramFile A)]) Int
doRefactor Text
"synth derived data types")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
simpleCompiler ()

ddtCheck :: CamfortEnv -> IO Int
ddtCheck :: CamfortEnv -> IO Int
ddtCheck =
  FileOrDir
-> AnalysisProgram
     FileOrDir () IO (ProgramFile A) DerivedDataTypeReport
-> AnalysisRunnerP
     FileOrDir
     ()
     IO
     (ProgramFile A)
     DerivedDataTypeReport
     (AnalysisReport FileOrDir () DerivedDataTypeReport)
-> MFCompiler () IO
-> ()
-> CamfortEnv
-> IO Int
forall e w b a i.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO Int
runFunctionalityP
  FileOrDir
"Checking derived datatype annotations"
  (PureAnalysis FileOrDir () DerivedDataTypeReport
-> AnalysisT FileOrDir () IO DerivedDataTypeReport
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (PureAnalysis FileOrDir () DerivedDataTypeReport
 -> AnalysisT FileOrDir () IO DerivedDataTypeReport)
-> (ProgramFile A
    -> PureAnalysis FileOrDir () DerivedDataTypeReport)
-> AnalysisProgram
     FileOrDir () IO (ProgramFile A) DerivedDataTypeReport
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramFile A -> PureAnalysis FileOrDir () DerivedDataTypeReport
DDT.check)
  (Text
-> AnalysisRunnerP
     FileOrDir
     ()
     IO
     (ProgramFile A)
     DerivedDataTypeReport
     (AnalysisReport FileOrDir () DerivedDataTypeReport)
forall (m :: * -> *) r w e.
(MonadIO m, Describe r, ExitCodeOfReport r, Describe w, Describe e,
 NFData e, NFData w, NFData r) =>
Text
-> AnalysisRunnerP e w m (ProgramFile A) r (AnalysisReport e w r)
describePerFileAnalysisP Text
"check derived datatypes")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
simpleCompiler ()

ddtInfer :: CamfortEnv -> IO Int
ddtInfer :: CamfortEnv -> IO Int
ddtInfer =
  FileOrDir
-> AnalysisProgram
     FileOrDir () IO (ProgramFile A) DerivedDataTypeReport
-> AnalysisRunnerP
     FileOrDir
     ()
     IO
     (ProgramFile A)
     DerivedDataTypeReport
     (AnalysisReport FileOrDir () DerivedDataTypeReport)
-> MFCompiler () IO
-> ()
-> CamfortEnv
-> IO Int
forall e w b a i.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO Int
runFunctionalityP
  FileOrDir
"Inferring derived datatypes"
  (PureAnalysis FileOrDir () DerivedDataTypeReport
-> AnalysisT FileOrDir () IO DerivedDataTypeReport
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (PureAnalysis FileOrDir () DerivedDataTypeReport
 -> AnalysisT FileOrDir () IO DerivedDataTypeReport)
-> (ProgramFile A
    -> PureAnalysis FileOrDir () DerivedDataTypeReport)
-> AnalysisProgram
     FileOrDir () IO (ProgramFile A) DerivedDataTypeReport
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramFile A -> PureAnalysis FileOrDir () DerivedDataTypeReport
DDT.infer)
  (Text
-> AnalysisRunnerP
     FileOrDir
     ()
     IO
     (ProgramFile A)
     DerivedDataTypeReport
     (AnalysisReport FileOrDir () DerivedDataTypeReport)
forall (m :: * -> *) r w e.
(MonadIO m, Describe r, ExitCodeOfReport r, Describe w, Describe e,
 NFData e, NFData w, NFData r) =>
Text
-> AnalysisRunnerP e w m (ProgramFile A) r (AnalysisReport e w r)
describePerFileAnalysisP Text
"infer derived datatypes")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
simpleCompiler ()

ddtCompile :: CamfortEnv -> IO Int
ddtCompile :: CamfortEnv -> IO Int
ddtCompile CamfortEnv
env = do
  let description :: FileOrDir
description = FileOrDir
"Compiling derived datatypes for"
  FileOrDir -> IO ()
putStrLn (FileOrDir -> IO ()) -> FileOrDir -> IO ()
forall a b. (a -> b) -> a -> b
$ FileOrDir
description FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
" '" FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ CamfortEnv -> FileOrDir
ceInputSources CamfortEnv
env FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
"'"
  FileOrDir
incDir' <- IO FileOrDir
-> (FileOrDir -> IO FileOrDir) -> Maybe FileOrDir -> IO FileOrDir
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO FileOrDir
getCurrentDirectory FileOrDir -> IO FileOrDir
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CamfortEnv -> Maybe FileOrDir
ceIncludeDir CamfortEnv
env)
  Bool
isDir <- FileOrDir -> IO Bool
doesDirectoryExist FileOrDir
incDir'
  let incDir :: FileOrDir
incDir | Bool
isDir     = FileOrDir
incDir'
             | Bool
otherwise = FileOrDir -> FileOrDir
takeDirectory FileOrDir
incDir'
  ModFiles
modFileNames <- FileOrDir -> IO ModFiles
getModFiles FileOrDir
incDir

  -- Run the gen mod file routine directly on the input source
  ModFiles
modFiles <- Maybe FortranVersion
-> ModFiles
-> MFCompiler () IO
-> ()
-> FileOrDir
-> [FileOrDir]
-> IO ModFiles
forall (m :: * -> *) r.
MonadIO m =>
Maybe FortranVersion
-> ModFiles
-> MFCompiler r m
-> r
-> FileOrDir
-> [FileOrDir]
-> m ModFiles
genModFiles (CamfortEnv -> Maybe FortranVersion
ceFortranVersion CamfortEnv
env) ModFiles
modFileNames MFCompiler () IO
DDT.compile () (CamfortEnv -> FileOrDir
ceInputSources CamfortEnv
env) (CamfortEnv -> [FileOrDir]
ceExcludeFiles CamfortEnv
env)
  -- Write the mod files out
  ModFiles -> (ModFile -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ ModFiles
modFiles ((ModFile -> IO ()) -> IO ()) -> (ModFile -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ ModFile
modFile -> do
     let mfname :: FileOrDir
mfname = FileOrDir -> FileOrDir -> FileOrDir
replaceExtension (ModFile -> FileOrDir
FM.moduleFilename ModFile
modFile) FileOrDir
FM.modFileSuffix
     FileOrDir -> ByteString -> IO ()
LB.writeFile FileOrDir
mfname (ModFiles -> ByteString
FM.encodeModFile [ModFile
modFile])
  Int -> IO Int
forall (m :: * -> *) a. Monad m => a -> m a
return Int
0

{- Units feature -}

runUnitsFunctionalityP
  :: (Describe e, Describe w, ExitCodeOfReport b)
  => String
  -> (UnitOpts -> AnalysisProgram e w IO a b)
  -> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
  -> LiteralsOpt
  -> CamfortEnv
  -> IO Int
runUnitsFunctionalityP :: FileOrDir
-> (UnitOpts -> AnalysisProgram e w IO a b)
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> LiteralsOpt
-> CamfortEnv
-> IO Int
runUnitsFunctionalityP FileOrDir
description UnitOpts -> AnalysisProgram e w IO a b
unitsProgram AnalysisRunnerP e w IO a b (AnalysisReport e w b)
runner LiteralsOpt
opts =
  let uo :: UnitOpts
uo = LiteralsOpt -> UnitOpts
optsToUnitOpts LiteralsOpt
opts
  in FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> MFCompiler UnitOpts IO
-> UnitOpts
-> CamfortEnv
-> IO Int
forall e w b a i.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO Int
runFunctionalityP FileOrDir
description (UnitOpts -> AnalysisProgram e w IO a b
unitsProgram UnitOpts
uo) AnalysisRunnerP e w IO a b (AnalysisReport e w b)
runner MFCompiler UnitOpts IO
compileUnits UnitOpts
uo

optsToUnitOpts :: LiteralsOpt -> UnitOpts
optsToUnitOpts :: LiteralsOpt -> UnitOpts
optsToUnitOpts LiteralsOpt
m = UnitOpts
o1
  where o1 :: UnitOpts
o1 = UnitOpts
unitOpts0 { uoLiterals :: LiteralsOpt
uoLiterals = LiteralsOpt
m
                       }

singlePfUnits
  :: UnitAnalysis a -> UnitOpts
  -> AnalysisProgram () () IO ProgramFile a
singlePfUnits :: UnitAnalysis a
-> UnitOpts -> AnalysisProgram () () IO (ProgramFile A) a
singlePfUnits UnitAnalysis a
unitAnalysis UnitOpts
opts ProgramFile A
pf =
  let ue :: UnitEnv
ue = UnitEnv :: UnitOpts -> ProgramFile A -> UnitEnv
UnitEnv
        { unitOpts :: UnitOpts
unitOpts = UnitOpts
opts
        , unitProgramFile :: ProgramFile A
unitProgramFile = ProgramFile A
pf
        }
  in UnitEnv -> UnitAnalysis a -> AnalysisT () () IO a
forall a. UnitEnv -> UnitAnalysis a -> AnalysisT () () IO a
runUnitAnalysis UnitEnv
ue UnitAnalysis a
unitAnalysis


-- slight hack to make doRefactorAndCreate happy
-- singlePfUnits'
--   :: UnitAnalysis a -> UnitOpts
--   -> AnalysisProgram () () IO [ProgramFile] a
-- singlePfUnits' unitAnalysis opts (pf:_) =
--   let ue = UnitEnv
--         { unitOpts = opts
--         , unitProgramFile = pf
--         }
--   in runUnitAnalysis ue unitAnalysis
-- singlePfUnits' _ _ [] = error "singlePfUnits': no program file provided"

multiPfUnits
  :: (Describe a)
  => UnitAnalysis (Either e (a, b))
  -> UnitOpts
  -> AnalysisProgram () () IO [ProgramFile] (Text, [Either e b])
multiPfUnits :: UnitAnalysis (Either e (a, b))
-> UnitOpts
-> AnalysisProgram () () IO [ProgramFile A] (Text, [Either e b])
multiPfUnits UnitAnalysis (Either e (a, b))
unitAnalysis UnitOpts
opts [ProgramFile A]
pfs = do
  let ue :: ProgramFile A -> UnitEnv
ue ProgramFile A
pf = UnitEnv :: UnitOpts -> ProgramFile A -> UnitEnv
UnitEnv
        { unitOpts :: UnitOpts
unitOpts = UnitOpts
opts
        , unitProgramFile :: ProgramFile A
unitProgramFile = ProgramFile A
pf
        }

  [Either e (a, b)]
results <- (ProgramFile A -> AnalysisT () () IO (Either e (a, b)))
-> [ProgramFile A] -> AnalysisT () () IO [Either e (a, b)]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (\ProgramFile A
pf -> UnitEnv
-> UnitAnalysis (Either e (a, b))
-> AnalysisT () () IO (Either e (a, b))
forall a. UnitEnv -> UnitAnalysis a -> AnalysisT () () IO a
runUnitAnalysis (ProgramFile A -> UnitEnv
ue ProgramFile A
pf) UnitAnalysis (Either e (a, b))
unitAnalysis) [ProgramFile A]
pfs
  let ([a]
rs, [Either e b]
ps) = (Either e (a, b) -> ([a], Either e b))
-> [Either e (a, b)] -> ([a], [Either e b])
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (((a, b) -> ([a], b)) -> Either e (a, b) -> ([a], Either e b)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (\(a
x, b
y) -> ([a
x], b
y))) [Either e (a, b)]
results

      rs' :: Text
rs' = [Text] -> Text
forall a. Monoid a => [a] -> a
mconcat ([Text] -> Text) -> ([a] -> [Text]) -> [a] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
intersperse Text
"\n" ([Text] -> [Text]) -> ([a] -> [Text]) -> [a] -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Text) -> [a] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map a -> Text
forall a. Describe a => a -> Text
describe ([a] -> Text) -> [a] -> Text
forall a b. (a -> b) -> a -> b
$ [a]
rs

  (Text, [Either e b]) -> AnalysisT () () IO (Text, [Either e b])
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
rs', [Either e b]
ps)

unitsDump :: LiteralsOpt -> CamfortEnv -> IO Int
unitsDump :: LiteralsOpt -> CamfortEnv -> IO Int
unitsDump LiteralsOpt
_ CamfortEnv
env = do
  let modFileName :: FileOrDir
modFileName = CamfortEnv -> FileOrDir
ceInputSources CamfortEnv
env
  ByteString
modData <- FileOrDir -> IO ByteString
LB.readFile FileOrDir
modFileName
  let eResult :: Either FileOrDir ModFiles
eResult = ByteString -> Either FileOrDir ModFiles
FM.decodeModFile ByteString
modData
  case Either FileOrDir ModFiles
eResult of
    Left FileOrDir
msg -> do
      FileOrDir -> IO ()
putStrLn (FileOrDir -> IO ()) -> FileOrDir -> IO ()
forall a b. (a -> b) -> a -> b
$ FileOrDir
modFileName FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
": Error: " FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir -> FileOrDir
forall a. Show a => a -> FileOrDir
show FileOrDir
msg
      Int -> IO Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
1
    Right ModFiles
modFiles -> do
      ModFiles -> (ModFile -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ ModFiles
modFiles ((ModFile -> IO ()) -> IO ()) -> (ModFile -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ ModFile
modFile -> do
        FileOrDir -> IO ()
putStrLn (FileOrDir -> IO ()) -> FileOrDir -> IO ()
forall a b. (a -> b) -> a -> b
$ FileOrDir
modFileName FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
": successfully parsed summary file."
        FileOrDir -> IO ()
putStrLn (FileOrDir -> IO ())
-> (Maybe FileOrDir -> FileOrDir) -> Maybe FileOrDir -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FileOrDir -> Maybe FileOrDir -> FileOrDir
forall a. a -> Maybe a -> a
fromMaybe FileOrDir
"unable to find units info" (Maybe FileOrDir -> IO ()) -> Maybe FileOrDir -> IO ()
forall a b. (a -> b) -> a -> b
$ ModFile -> Maybe FileOrDir
dumpModFileCompiledUnits ModFile
modFile
      Int -> IO Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
0

unitsCheck :: LiteralsOpt -> CamfortEnv -> IO Int
unitsCheck :: LiteralsOpt -> CamfortEnv -> IO Int
unitsCheck =
  FileOrDir
-> (UnitOpts
    -> AnalysisProgram () () IO (ProgramFile A) ConsistencyReport)
-> AnalysisRunnerP
     ()
     ()
     IO
     (ProgramFile A)
     ConsistencyReport
     (AnalysisReport () () ConsistencyReport)
-> LiteralsOpt
-> CamfortEnv
-> IO Int
forall e w b a.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> (UnitOpts -> AnalysisProgram e w IO a b)
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> LiteralsOpt
-> CamfortEnv
-> IO Int
runUnitsFunctionalityP
  FileOrDir
"Checking units for"
  (UnitAnalysis ConsistencyReport
-> UnitOpts
-> AnalysisProgram () () IO (ProgramFile A) ConsistencyReport
forall a.
UnitAnalysis a
-> UnitOpts -> AnalysisProgram () () IO (ProgramFile A) a
singlePfUnits UnitAnalysis ConsistencyReport
checkUnits)
  (Text
-> AnalysisRunnerP
     ()
     ()
     IO
     (ProgramFile A)
     ConsistencyReport
     (AnalysisReport () () ConsistencyReport)
forall (m :: * -> *) r w e.
(MonadIO m, Describe r, ExitCodeOfReport r, Describe w, Describe e,
 NFData e, NFData w, NFData r) =>
Text
-> AnalysisRunnerP e w m (ProgramFile A) r (AnalysisReport e w r)
describePerFileAnalysisP Text
"unit checking")


unitsInfer :: Bool -> LiteralsOpt -> CamfortEnv -> IO Int
unitsInfer :: Bool -> LiteralsOpt -> CamfortEnv -> IO Int
unitsInfer Bool
showAST =
  FileOrDir
-> (UnitOpts
    -> AnalysisProgram () () IO (ProgramFile A) InferenceResult)
-> AnalysisRunnerP
     ()
     ()
     IO
     (ProgramFile A)
     InferenceResult
     (AnalysisReport () () InferenceResult)
-> LiteralsOpt
-> CamfortEnv
-> IO Int
forall e w b a.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> (UnitOpts -> AnalysisProgram e w IO a b)
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> LiteralsOpt
-> CamfortEnv
-> IO Int
runUnitsFunctionalityP
  FileOrDir
"Inferring units for"
  (UnitAnalysis InferenceResult
-> UnitOpts
-> AnalysisProgram () () IO (ProgramFile A) InferenceResult
forall a.
UnitAnalysis a
-> UnitOpts -> AnalysisProgram () () IO (ProgramFile A) a
singlePfUnits UnitAnalysis InferenceResult
inferUnits)
  (if Bool
showAST
      then AnalysisRunnerP
  ()
  ()
  IO
  (ProgramFile A)
  InferenceResult
  (AnalysisReport () () InferenceResult)
forall (m :: * -> *) w e.
(MonadIO m, Describe w, Describe e, NFData w, NFData e) =>
AnalysisRunnerP
  e
  w
  m
  (ProgramFile A)
  InferenceResult
  (AnalysisReport e w InferenceResult)
describePerFileAnalysisShowASTUnitInfoP
      else Text
-> AnalysisRunnerP
     ()
     ()
     IO
     (ProgramFile A)
     InferenceResult
     (AnalysisReport () () InferenceResult)
forall (m :: * -> *) r w e.
(MonadIO m, Describe r, ExitCodeOfReport r, Describe w, Describe e,
 NFData e, NFData w, NFData r) =>
Text
-> AnalysisRunnerP e w m (ProgramFile A) r (AnalysisReport e w r)
describePerFileAnalysisP Text
"unit inference")

-- | Given an analysis program for a single file, run it over every input file
-- and collect the reports, then print those reports to standard output.
describePerFileAnalysisShowASTUnitInfoP
  :: (MonadIO m, Describe w, Describe e, NFData w, NFData e)
  => AnalysisRunnerP e w m ProgramFile InferenceResult (AnalysisReport e w InferenceResult)
describePerFileAnalysisShowASTUnitInfoP :: AnalysisRunnerP
  e
  w
  m
  (ProgramFile A)
  InferenceResult
  (AnalysisReport e w InferenceResult)
describePerFileAnalysisShowASTUnitInfoP AnalysisProgram e w m (ProgramFile A) InferenceResult
program LogOutput m
logOutput LogLevel
logLevel Bool
snippets ModFiles
modFiles =
  AnalysisRunnerP
  e
  w
  m
  (ProgramFile A)
  InferenceResult
  (AnalysisReport e w InferenceResult)
forall (m :: * -> *) e w b.
(MonadIO m, Describe e, Describe w, NFData e, NFData w,
 NFData b) =>
AnalysisRunnerP e w m (ProgramFile A) b (AnalysisReport e w b)
runPerFileAnalysisP AnalysisProgram e w m (ProgramFile A) InferenceResult
program LogOutput m
logOutput LogLevel
logLevel Bool
snippets ModFiles
modFiles Proxy
  ()
  (ProgramFile A, SourceText)
  ()
  (AnalysisReport e w InferenceResult)
  m
  ()
-> Proxy
     ()
     (AnalysisReport e w InferenceResult)
     ()
     (AnalysisReport e w InferenceResult)
     m
     ()
-> Proxy
     ()
     (ProgramFile A, SourceText)
     ()
     (AnalysisReport e w InferenceResult)
     m
     ()
forall (m :: * -> *) a' a b r c' c.
Functor m =>
Proxy a' a () b m r -> Proxy () b c' c m r -> Proxy a' a c' c m r
>->
    ((AnalysisReport e w InferenceResult
 -> m (AnalysisReport e w InferenceResult))
-> Proxy
     ()
     (AnalysisReport e w InferenceResult)
     ()
     (AnalysisReport e w InferenceResult)
     m
     ()
forall (m :: * -> *) a b r. Monad m => (a -> m b) -> Pipe a b m r
P.mapM ((AnalysisReport e w InferenceResult
  -> m (AnalysisReport e w InferenceResult))
 -> Proxy
      ()
      (AnalysisReport e w InferenceResult)
      ()
      (AnalysisReport e w InferenceResult)
      m
      ())
-> (AnalysisReport e w InferenceResult
    -> m (AnalysisReport e w InferenceResult))
-> Proxy
     ()
     (AnalysisReport e w InferenceResult)
     ()
     (AnalysisReport e w InferenceResult)
     m
     ()
forall a b. (a -> b) -> a -> b
$ \ AnalysisReport e w InferenceResult
r -> do
        case AnalysisReport e w InferenceResult
r of
          AnalysisReport FileOrDir
_ [SomeMessage e w]
_ (ARSuccess (Inferred (InferenceReport ProgramFile UA
pfUA [(VV, UnitInfo)]
_))) ->
            IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ())
-> (ProgramFile UA -> IO ()) -> ProgramFile UA -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramFile (Maybe UnitInfo) -> IO ()
forall a. Out a => a -> IO ()
pp (ProgramFile (Maybe UnitInfo) -> IO ())
-> (ProgramFile UA -> ProgramFile (Maybe UnitInfo))
-> ProgramFile UA
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UA -> Maybe UnitInfo)
-> ProgramFile UA -> ProgramFile (Maybe UnitInfo)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (UnitAnnotation A -> Maybe UnitInfo
forall a. UnitAnnotation a -> Maybe UnitInfo
unitInfo (UnitAnnotation A -> Maybe UnitInfo)
-> (UA -> UnitAnnotation A) -> UA -> Maybe UnitInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UA -> UnitAnnotation A
forall a. Analysis a -> a
FA.prevAnnotation) (ProgramFile UA -> ProgramFile (Maybe UnitInfo))
-> (ProgramFile UA -> ProgramFile UA)
-> ProgramFile UA
-> ProgramFile (Maybe UnitInfo)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramFile UA -> ProgramFile UA
forall a.
Data a =>
ProgramFile (Analysis a) -> ProgramFile (Analysis a)
FA.rename (ProgramFile UA -> m ()) -> ProgramFile UA -> m ()
forall a b. (a -> b) -> a -> b
$ ProgramFile UA
pfUA
          AnalysisReport e w InferenceResult
_ -> () -> m ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
        Text
-> Maybe LogLevel
-> Bool
-> AnalysisReport e w InferenceResult
-> m ()
forall e w r (m :: * -> *).
(Describe e, Describe w, Describe r, MonadIO m) =>
Text -> Maybe LogLevel -> Bool -> AnalysisReport e w r -> m ()
putDescribeReport Text
"unit inference" (LogLevel -> Maybe LogLevel
forall a. a -> Maybe a
Just LogLevel
logLevel) Bool
snippets AnalysisReport e w InferenceResult
r
        AnalysisReport e w InferenceResult
-> m (AnalysisReport e w InferenceResult)
forall (f :: * -> *) a. Applicative f => a -> f a
pure AnalysisReport e w InferenceResult
r)

-- | Expand all paths that are directories into a list of Fortran
-- files from a recursive directory listing.
expandDirs :: [FilePath] -> IO [FilePath]
expandDirs :: [FileOrDir] -> IO [FileOrDir]
expandDirs = ([[FileOrDir]] -> [FileOrDir])
-> IO [[FileOrDir]] -> IO [FileOrDir]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [[FileOrDir]] -> [FileOrDir]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (IO [[FileOrDir]] -> IO [FileOrDir])
-> ([FileOrDir] -> IO [[FileOrDir]])
-> [FileOrDir]
-> IO [FileOrDir]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FileOrDir -> IO [FileOrDir]) -> [FileOrDir] -> IO [[FileOrDir]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM FileOrDir -> IO [FileOrDir]
doEach
  where
    doEach :: FileOrDir -> IO [FileOrDir]
doEach FileOrDir
path = do
      Bool
isDir <- FileOrDir -> IO Bool
doesDirectoryExist FileOrDir
path
      if Bool
isDir
        then FileOrDir -> IO [FileOrDir]
listFortranFiles FileOrDir
path
        else [FileOrDir] -> IO [FileOrDir]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [FileOrDir
path]

-- | Get a list of Fortran files under the given directory.
listFortranFiles :: FilePath -> IO [FilePath]
listFortranFiles :: FileOrDir -> IO [FileOrDir]
listFortranFiles FileOrDir
dir = (FileOrDir -> Bool) -> [FileOrDir] -> [FileOrDir]
forall a. (a -> Bool) -> [a] -> [a]
filter FileOrDir -> Bool
isFortran ([FileOrDir] -> [FileOrDir]) -> IO [FileOrDir] -> IO [FileOrDir]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FileOrDir -> IO [FileOrDir]
listDirectoryRecursively FileOrDir
dir
  where
    -- | True if the file has a valid fortran extension.
    isFortran :: FilePath -> Bool
    isFortran :: FileOrDir -> Bool
isFortran FileOrDir
x = (Char -> Char) -> FileOrDir -> FileOrDir
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower (FileOrDir -> FileOrDir
takeExtension FileOrDir
x) FileOrDir -> [FileOrDir] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [FileOrDir]
exts
      where exts :: [FileOrDir]
exts = [FileOrDir
".f", FileOrDir
".f90", FileOrDir
".f77", FileOrDir
".f03"]

listDirectoryRecursively :: FilePath -> IO [FilePath]
listDirectoryRecursively :: FileOrDir -> IO [FileOrDir]
listDirectoryRecursively FileOrDir
dir = FileOrDir -> FileOrDir -> IO [FileOrDir]
listDirectoryRec FileOrDir
dir FileOrDir
""
  where
    listDirectoryRec :: FilePath -> FilePath -> IO [FilePath]
    listDirectoryRec :: FileOrDir -> FileOrDir -> IO [FileOrDir]
listDirectoryRec FileOrDir
d FileOrDir
f = do
      let fullPath :: FileOrDir
fullPath = FileOrDir
d FileOrDir -> FileOrDir -> FileOrDir
</> FileOrDir
f
      Bool
isDir <- FileOrDir -> IO Bool
doesDirectoryExist FileOrDir
fullPath
      if Bool
isDir
      then do
        [FileOrDir]
conts <- FileOrDir -> IO [FileOrDir]
listDirectory FileOrDir
fullPath
        [[FileOrDir]] -> [FileOrDir]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[FileOrDir]] -> [FileOrDir])
-> IO [[FileOrDir]] -> IO [FileOrDir]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (FileOrDir -> IO [FileOrDir]) -> [FileOrDir] -> IO [[FileOrDir]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (FileOrDir -> FileOrDir -> IO [FileOrDir]
listDirectoryRec FileOrDir
fullPath) [FileOrDir]
conts
      else [FileOrDir] -> IO [FileOrDir]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [FileOrDir
fullPath]

decodeOneModFile :: FilePath -> IO FM.ModFiles
decodeOneModFile :: FileOrDir -> IO ModFiles
decodeOneModFile FileOrDir
path = do
  ByteString
contents <- FileOrDir -> IO ByteString
LB.readFile FileOrDir
path
  case ByteString -> Either FileOrDir ModFiles
FM.decodeModFile ByteString
contents of
    Left FileOrDir
msg -> do
      Handle -> FileOrDir -> IO ()
hPutStrLn Handle
stderr (FileOrDir -> IO ()) -> FileOrDir -> IO ()
forall a b. (a -> b) -> a -> b
$ FileOrDir
path FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
": Error: " FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
msg
      ModFiles -> IO ModFiles
forall (m :: * -> *) a. Monad m => a -> m a
return []
    Right ModFiles
modFiles -> do
      Handle -> FileOrDir -> IO ()
hPutStrLn Handle
stderr (FileOrDir -> IO ()) -> FileOrDir -> IO ()
forall a b. (a -> b) -> a -> b
$ FileOrDir
path FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
": successfully parsed summary file."
      ModFiles -> IO ModFiles
forall (m :: * -> *) a. Monad m => a -> m a
return ModFiles
modFiles

unitsCompile :: LiteralsOpt -> CamfortEnv -> IO Int
unitsCompile :: LiteralsOpt -> CamfortEnv -> IO Int
unitsCompile LiteralsOpt
opts CamfortEnv
env = do
  let uo :: UnitOpts
uo = LiteralsOpt -> UnitOpts
optsToUnitOpts LiteralsOpt
opts
  let description :: FileOrDir
description = FileOrDir
"Compiling units for"
  FileOrDir -> IO ()
putStrLn (FileOrDir -> IO ()) -> FileOrDir -> IO ()
forall a b. (a -> b) -> a -> b
$ FileOrDir
description FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
" '" FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ CamfortEnv -> FileOrDir
ceInputSources CamfortEnv
env FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
"'"
  FileOrDir
incDir' <- IO FileOrDir
-> (FileOrDir -> IO FileOrDir) -> Maybe FileOrDir -> IO FileOrDir
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO FileOrDir
getCurrentDirectory FileOrDir -> IO FileOrDir
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CamfortEnv -> Maybe FileOrDir
ceIncludeDir CamfortEnv
env)
  Bool
isDir <- FileOrDir -> IO Bool
doesDirectoryExist FileOrDir
incDir'
  let incDir :: FileOrDir
incDir | Bool
isDir     = FileOrDir
incDir'
             | Bool
otherwise = FileOrDir -> FileOrDir
takeDirectory FileOrDir
incDir'
  -- modFileNames <- getModFiles incDir

  [FileOrDir]
paths' <- [FileOrDir] -> IO [FileOrDir]
expandDirs ([FileOrDir] -> IO [FileOrDir]) -> [FileOrDir] -> IO [FileOrDir]
forall a b. (a -> b) -> a -> b
$ [CamfortEnv -> FileOrDir
ceInputSources CamfortEnv
env]
  -- Build the graph of module dependencies
  ModGraph
mg0 <- Maybe FortranVersion -> [FileOrDir] -> [FileOrDir] -> IO ModGraph
FM.genModGraph (CamfortEnv -> Maybe FortranVersion
ceFortranVersion CamfortEnv
env) [FileOrDir
incDir] [FileOrDir]
paths'

  let compileFileToMod :: ModFiles -> ProgramFile A -> IO ModFile
compileFileToMod ModFiles
mods ProgramFile A
pf = do
        ModFile
mod <- MFCompiler UnitOpts IO
compileUnits UnitOpts
uo ModFiles
mods ProgramFile A
pf
        let mfname :: FileOrDir
mfname = FileOrDir -> FileOrDir -> FileOrDir
replaceExtension (ModFile -> FileOrDir
FM.moduleFilename ModFile
mod) FileOrDir
FM.modFileSuffix
        FileOrDir -> ByteString -> IO ()
LB.writeFile FileOrDir
mfname (ModFiles -> ByteString
FM.encodeModFile [ModFile
mod])
        ModFile -> IO ModFile
forall (f :: * -> *) a. Applicative f => a -> f a
pure ModFile
mod

  -- Loop through the dependency graph until it is empty
  let loop :: ModGraph -> ModFiles -> IO ModFiles
loop ModGraph
mg ModFiles
mods
        | [(Int, Maybe ModOrigin)]
nxt <- ModGraph -> [(Int, Maybe ModOrigin)]
FM.takeNextMods ModGraph
mg
        , Bool -> Bool
not ([(Int, Maybe ModOrigin)] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(Int, Maybe ModOrigin)]
nxt) = do
            let fnPaths :: [FileOrDir]
fnPaths = [ FileOrDir
fn | (Int
_, Just (FM.MOFile FileOrDir
fn)) <- [(Int, Maybe ModOrigin)]
nxt ]
            ModFiles
newMods <- ([ModFiles] -> ModFiles) -> IO [ModFiles] -> IO ModFiles
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [ModFiles] -> ModFiles
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (IO [ModFiles] -> IO ModFiles)
-> ((FileOrDir -> IO ModFiles) -> IO [ModFiles])
-> (FileOrDir -> IO ModFiles)
-> IO ModFiles
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [FileOrDir] -> (FileOrDir -> IO ModFiles) -> IO [ModFiles]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [FileOrDir]
fnPaths ((FileOrDir -> IO ModFiles) -> IO ModFiles)
-> (FileOrDir -> IO ModFiles) -> IO ModFiles
forall a b. (a -> b) -> a -> b
$ \ FileOrDir
fnPath -> do
              TimestampStatus
tsStatus <- FileOrDir -> IO TimestampStatus
FM.checkTimestamps FileOrDir
fnPath
              case TimestampStatus
tsStatus of
                TimestampStatus
FM.NoSuchFile -> do
                  FileOrDir -> IO ()
putStr (FileOrDir -> IO ()) -> FileOrDir -> IO ()
forall a b. (a -> b) -> a -> b
$ FileOrDir
"Does not exist: " FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
fnPath
                  ModFiles -> IO ModFiles
forall (f :: * -> *) a. Applicative f => a -> f a
pure [ModFile
FM.emptyModFile]
                FM.ModFileExists FileOrDir
modPath -> do
                  FileOrDir -> IO ()
putStrLn (FileOrDir -> IO ()) -> FileOrDir -> IO ()
forall a b. (a -> b) -> a -> b
$ FileOrDir
"Loading mod file " FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
modPath FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
"."
                  FileOrDir -> IO ModFiles
decodeOneModFile FileOrDir
modPath
                TimestampStatus
FM.CompileFile -> do
                  FileOrDir -> IO ()
putStr (FileOrDir -> IO ()) -> FileOrDir -> IO ()
forall a b. (a -> b) -> a -> b
$ FileOrDir
"Summarising " FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
fnPath FileOrDir -> FileOrDir -> FileOrDir
forall a. [a] -> [a] -> [a]
++ FileOrDir
"..."
                  Maybe (ProgramFile A, SourceText)
m_pf <- Maybe FortranVersion
-> ModFiles -> FileOrDir -> IO (Maybe (ProgramFile A, SourceText))
readParseSrcFile (CamfortEnv -> Maybe FortranVersion
ceFortranVersion CamfortEnv
env) ModFiles
mods FileOrDir
fnPath
                  case Maybe (ProgramFile A, SourceText)
m_pf of
                    Just (ProgramFile A
pf, SourceText
_) -> do
                      ModFile
mod <- ModFiles -> ProgramFile A -> IO ModFile
compileFileToMod ModFiles
mods ProgramFile A
pf
                      FileOrDir -> IO ()
putStrLn FileOrDir
"done"
                      ModFiles -> IO ModFiles
forall (f :: * -> *) a. Applicative f => a -> f a
pure [ModFile
mod]
                    Maybe (ProgramFile A, SourceText)
Nothing -> do
                      FileOrDir -> IO ()
putStrLn FileOrDir
"failed"
                      ModFiles -> IO ModFiles
forall (f :: * -> *) a. Applicative f => a -> f a
pure []

            let ns :: [Int]
ns  = ((Int, Maybe ModOrigin) -> Int)
-> [(Int, Maybe ModOrigin)] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int, Maybe ModOrigin) -> Int
forall a b. (a, b) -> a
fst [(Int, Maybe ModOrigin)]
nxt
            let mg' :: ModGraph
mg' = [Int] -> ModGraph -> ModGraph
FM.delModNodes [Int]
ns ModGraph
mg
            ModGraph -> ModFiles -> IO ModFiles
loop ModGraph
mg' (ModFiles -> IO ModFiles) -> ModFiles -> IO ModFiles
forall a b. (a -> b) -> a -> b
$ ModFiles
newMods ModFiles -> ModFiles -> ModFiles
forall a. [a] -> [a] -> [a]
++ ModFiles
mods
      loop ModGraph
_ ModFiles
mods = ModFiles -> IO ModFiles
forall (f :: * -> *) a. Applicative f => a -> f a
pure ModFiles
mods

  ModFiles
_allMods <- ModGraph -> ModFiles -> IO ModFiles
loop ModGraph
mg0 []
  Int -> IO Int
forall (m :: * -> *) a. Monad m => a -> m a
return Int
0

unitsSynth :: AnnotationType -> FileOrDir -> LiteralsOpt -> CamfortEnv -> IO Int
unitsSynth :: AnnotationType -> FileOrDir -> LiteralsOpt -> CamfortEnv -> IO Int
unitsSynth AnnotationType
annType FileOrDir
outSrc LiteralsOpt
opts CamfortEnv
env =
  FileOrDir
-> AnalysisProgram
     ()
     ()
     IO
     [ProgramFile A]
     (Text, [Either ConsistencyError (ProgramFile A)])
-> AnalysisRunner
     ()
     ()
     IO
     [ProgramFile A]
     (Text, [Either ConsistencyError (ProgramFile A)])
     Int
-> MFCompiler UnitOpts IO
-> UnitOpts
-> CamfortEnv
-> IO Int
forall e w a b r i.
(Describe e, Describe w) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunner e w IO a b r
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO r
runFunctionality FileOrDir
"Synthesising units for"
                   (UnitAnalysis
  (Either ConsistencyError (InferenceReport, ProgramFile A))
-> UnitOpts
-> AnalysisProgram
     ()
     ()
     IO
     [ProgramFile A]
     (Text, [Either ConsistencyError (ProgramFile A)])
forall a e b.
Describe a =>
UnitAnalysis (Either e (a, b))
-> UnitOpts
-> AnalysisProgram () () IO [ProgramFile A] (Text, [Either e b])
multiPfUnits (Char
-> UnitAnalysis
     (Either ConsistencyError (InferenceReport, ProgramFile A))
LU.synthesiseUnits (AnnotationType -> Char
markerChar AnnotationType
annType)) UnitOpts
uo)
                   (Text
-> FileOrDir
-> FileOrDir
-> AnalysisRunner
     ()
     ()
     IO
     [ProgramFile A]
     (Text, [Either ConsistencyError (ProgramFile A)])
     Int
forall e e' w r.
(Describe e, Describe e', Describe w, Describe r,
 ExitCodeOfReport r) =>
Text
-> FileOrDir
-> FileOrDir
-> AnalysisRunner
     e w IO [ProgramFile A] (r, [Either e' (ProgramFile A)]) Int
doRefactor Text
"unit synthesis" (CamfortEnv -> FileOrDir
ceInputSources CamfortEnv
env) FileOrDir
outSrc)
                   MFCompiler UnitOpts IO
compileUnits
                   UnitOpts
uo
                   CamfortEnv
env
  where uo :: UnitOpts
uo = LiteralsOpt -> UnitOpts
optsToUnitOpts LiteralsOpt
opts

unitsCriticals :: LiteralsOpt -> CamfortEnv -> IO Int
unitsCriticals :: LiteralsOpt -> CamfortEnv -> IO Int
unitsCriticals =
  FileOrDir
-> (UnitOpts -> AnalysisProgram () () IO (ProgramFile A) Criticals)
-> AnalysisRunnerP
     () () IO (ProgramFile A) Criticals (AnalysisReport () () Criticals)
-> LiteralsOpt
-> CamfortEnv
-> IO Int
forall e w b a.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> (UnitOpts -> AnalysisProgram e w IO a b)
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> LiteralsOpt
-> CamfortEnv
-> IO Int
runUnitsFunctionalityP
  FileOrDir
"Suggesting variables to annotate with unit specifications in"
  (UnitAnalysis Criticals
-> UnitOpts -> AnalysisProgram () () IO (ProgramFile A) Criticals
forall a.
UnitAnalysis a
-> UnitOpts -> AnalysisProgram () () IO (ProgramFile A) a
singlePfUnits UnitAnalysis Criticals
inferCriticalVariables)
  (Text
-> AnalysisRunnerP
     () () IO (ProgramFile A) Criticals (AnalysisReport () () Criticals)
forall (m :: * -> *) r w e.
(MonadIO m, Describe r, ExitCodeOfReport r, Describe w, Describe e,
 NFData e, NFData w, NFData r) =>
Text
-> AnalysisRunnerP e w m (ProgramFile A) r (AnalysisReport e w r)
describePerFileAnalysisP Text
"unit critical variable analysis")


{- Stencils feature -}


stencilsCheck :: CamfortEnv -> IO Int
stencilsCheck :: CamfortEnv -> IO Int
stencilsCheck =
  FileOrDir
-> AnalysisProgram () () IO (ProgramFile A) CheckResult
-> AnalysisRunnerP
     ()
     ()
     IO
     (ProgramFile A)
     CheckResult
     (AnalysisReport () () CheckResult)
-> MFCompiler () IO
-> ()
-> CamfortEnv
-> IO Int
forall e w b a i.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO Int
runFunctionalityP
  FileOrDir
"Checking stencil specs for"
  (PureAnalysis () () CheckResult -> AnalysisT () () IO CheckResult
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (PureAnalysis () () CheckResult -> AnalysisT () () IO CheckResult)
-> (ProgramFile A -> PureAnalysis () () CheckResult)
-> AnalysisProgram () () IO (ProgramFile A) CheckResult
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramFile A -> PureAnalysis () () CheckResult
Stencils.check)
  (Text
-> AnalysisRunnerP
     ()
     ()
     IO
     (ProgramFile A)
     CheckResult
     (AnalysisReport () () CheckResult)
forall (m :: * -> *) r w e.
(MonadIO m, Describe r, ExitCodeOfReport r, Describe w, Describe e,
 NFData e, NFData w, NFData r) =>
Text
-> AnalysisRunnerP e w m (ProgramFile A) r (AnalysisReport e w r)
describePerFileAnalysisP Text
"stencil checking")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
compileStencils ()


stencilsInfer :: Bool -> CamfortEnv -> IO Int
stencilsInfer :: Bool -> CamfortEnv -> IO Int
stencilsInfer Bool
useEval =
  FileOrDir
-> AnalysisProgram () () IO (ProgramFile A) StencilsReport
-> AnalysisRunnerP
     ()
     ()
     IO
     (ProgramFile A)
     StencilsReport
     (AnalysisReport () () StencilsReport)
-> MFCompiler () IO
-> ()
-> CamfortEnv
-> IO Int
forall e w b a i.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO Int
runFunctionalityP
  FileOrDir
"Inferring stencil specs for"
  (PureAnalysis () () StencilsReport
-> AnalysisT () () IO StencilsReport
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (PureAnalysis () () StencilsReport
 -> AnalysisT () () IO StencilsReport)
-> (ProgramFile A -> PureAnalysis () () StencilsReport)
-> AnalysisProgram () () IO (ProgramFile A) StencilsReport
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Char -> ProgramFile A -> PureAnalysis () () StencilsReport
Stencils.infer Bool
useEval Char
'=')
  (Text
-> AnalysisRunnerP
     ()
     ()
     IO
     (ProgramFile A)
     StencilsReport
     (AnalysisReport () () StencilsReport)
forall (m :: * -> *) r w e.
(MonadIO m, Describe r, ExitCodeOfReport r, Describe w, Describe e,
 NFData e, NFData w, NFData r) =>
Text
-> AnalysisRunnerP e w m (ProgramFile A) r (AnalysisReport e w r)
describePerFileAnalysisP Text
"stencil inference")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
compileStencils ()


stencilsSynth :: AnnotationType -> FileOrDir -> CamfortEnv -> IO Int
stencilsSynth :: AnnotationType -> FileOrDir -> CamfortEnv -> IO Int
stencilsSynth AnnotationType
annType =
  let
    program :: AnalysisProgram () () IO [ProgramFile] ((), [Either () ProgramFile])
    program :: AnalysisProgram
  () () IO [ProgramFile A] ((), [Either () (ProgramFile A)])
program [ProgramFile A]
pfs = PureAnalysis () () ((), [Either () (ProgramFile A)])
-> AnalysisT () () IO ((), [Either () (ProgramFile A)])
forall (m :: * -> *) e w a.
Monad m =>
PureAnalysis e w a -> AnalysisT e w m a
generalizePureAnalysis (PureAnalysis () () ((), [Either () (ProgramFile A)])
 -> AnalysisT () () IO ((), [Either () (ProgramFile A)]))
-> PureAnalysis () () ((), [Either () (ProgramFile A)])
-> AnalysisT () () IO ((), [Either () (ProgramFile A)])
forall a b. (a -> b) -> a -> b
$ do
      [ProgramFile A]
pfs' <- Char -> [ProgramFile A] -> StencilsAnalysis [ProgramFile A]
Stencils.synth (AnnotationType -> Char
markerChar AnnotationType
annType) [ProgramFile A]
pfs
      ((), [Either () (ProgramFile A)])
-> PureAnalysis () () ((), [Either () (ProgramFile A)])
forall (m :: * -> *) a. Monad m => a -> m a
return ((), (ProgramFile A -> Either () (ProgramFile A))
-> [ProgramFile A] -> [Either () (ProgramFile A)]
forall a b. (a -> b) -> [a] -> [b]
map ProgramFile A -> Either () (ProgramFile A)
forall a b. b -> Either a b
Right [ProgramFile A]
pfs')

  in FileOrDir
-> AnalysisProgram
     () () IO [ProgramFile A] ((), [Either () (ProgramFile A)])
-> (FileOrDir
    -> FileOrDir
    -> AnalysisRunner
         () () IO [ProgramFile A] ((), [Either () (ProgramFile A)]) Int)
-> MFCompiler () IO
-> ()
-> FileOrDir
-> CamfortEnv
-> IO Int
forall e w a b r i.
(Describe e, Describe w) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> (FileOrDir -> FileOrDir -> AnalysisRunner e w IO a b r)
-> MFCompiler i IO
-> i
-> FileOrDir
-> CamfortEnv
-> IO r
runWithOutput
     FileOrDir
"Synthesising stencil specs for"
     AnalysisProgram
  () () IO [ProgramFile A] ((), [Either () (ProgramFile A)])
program
     (Text
-> FileOrDir
-> FileOrDir
-> AnalysisRunner
     () () IO [ProgramFile A] ((), [Either () (ProgramFile A)]) Int
forall e e' w r.
(Describe e, Describe e', Describe w, Describe r,
 ExitCodeOfReport r) =>
Text
-> FileOrDir
-> FileOrDir
-> AnalysisRunner
     e w IO [ProgramFile A] (r, [Either e' (ProgramFile A)]) Int
doRefactor Text
"stencil synthesis")
     MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
compileStencils ()

{- Invariants Feature-}

invariantsCheck :: Hoare.PrimReprOption -> CamfortEnv -> IO Int
invariantsCheck :: PrimReprOption -> CamfortEnv -> IO Int
invariantsCheck PrimReprOption
pro =
  FileOrDir
-> AnalysisProgram
     HoareFrontendError
     HoareFrontendWarning
     IO
     (ProgramFile A)
     HoareCheckResults
-> AnalysisRunnerP
     HoareFrontendError
     HoareFrontendWarning
     IO
     (ProgramFile A)
     HoareCheckResults
     (AnalysisReport
        HoareFrontendError HoareFrontendWarning HoareCheckResults)
-> MFCompiler () IO
-> ()
-> CamfortEnv
-> IO Int
forall e w b a i.
(Describe e, Describe w, ExitCodeOfReport b) =>
FileOrDir
-> AnalysisProgram e w IO a b
-> AnalysisRunnerP e w IO a b (AnalysisReport e w b)
-> MFCompiler i IO
-> i
-> CamfortEnv
-> IO Int
runFunctionalityP
  FileOrDir
"Checking invariants in"
  (PrimReprOption
-> AnalysisProgram
     HoareFrontendError
     HoareFrontendWarning
     IO
     (ProgramFile A)
     HoareCheckResults
Hoare.check PrimReprOption
pro)
  (Text
-> AnalysisRunnerP
     HoareFrontendError
     HoareFrontendWarning
     IO
     (ProgramFile A)
     HoareCheckResults
     (AnalysisReport
        HoareFrontendError HoareFrontendWarning HoareCheckResults)
forall (m :: * -> *) r w e.
(MonadIO m, Describe r, ExitCodeOfReport r, Describe w, Describe e,
 NFData e, NFData w, NFData r) =>
Text
-> AnalysisRunnerP e w m (ProgramFile A) r (AnalysisReport e w r)
describePerFileAnalysisP Text
"invariant checking")
  MFCompiler () IO
forall (m :: * -> *). Monad m => MFCompiler () m
simpleCompiler ()


-- | Initialize Camfort for the given project.
camfortInitialize :: FilePath -> IO ()
camfortInitialize :: FileOrDir -> IO ()
camfortInitialize FileOrDir
projectDir =
  Bool -> FileOrDir -> IO ()
createDirectoryIfMissing Bool
False (FileOrDir
projectDir FileOrDir -> FileOrDir -> FileOrDir
</> FileOrDir
".camfort")