module Camfort.Functionality where
import System.FilePath
import Control.Monad
import Data.Generics.Uniplate.Operations
import Data.Data
import Data.Binary
import Data.Text (pack, unpack, split)
import Camfort.Analysis.Simple
import Camfort.Transformation.DataTypeIntroduction
import Camfort.Transformation.DeadCode
import Camfort.Transformation.CommonBlockElim
import Camfort.Transformation.EquivalenceElim
import qualified Camfort.Specification.Units as LU
import Camfort.Specification.Units.Monad
import Camfort.Helpers
import Camfort.Input
import qualified Language.Fortran.Parser.Any as FP
import Language.Fortran.Util.ModFile
import qualified Camfort.Specification.Stencils as Stencils
import qualified Data.Map.Strict as M
data Flag = Version
| Input String
| Output String
| Excludes String
| IncludeDir String
| Literals LiteralsOpt
| StencilInferMode Stencils.InferMode
| Doxygen
| Ford
| FVersion String
| RefactorInPlace
| Debug deriving (Data, Show, Eq)
type Options = [Flag]
instance Default String where
defaultValue = ""
getExcludes :: Options -> String
getExcludes opts = head ([ e | Excludes e <- universeBi opts ] ++ [""])
getExcludedFiles :: Options -> [String]
getExcludedFiles = map unpack . split (==',') . pack . getExcludes
ast d excludes _ _ = do
xs <- readParseSrcDir d excludes
print (map (\(_, _, p) -> p) xs)
countVarDecls inSrc excludes _ _ = do
putStrLn $ "Counting variable declarations in '" ++ inSrc ++ "'"
doAnalysisSummary countVariableDeclarations inSrc excludes Nothing
dead inSrc excludes outSrc _ = do
putStrLn $ "Eliminating dead code in '" ++ inSrc ++ "'"
report <- doRefactor (mapM (deadCode False)) inSrc excludes outSrc
putStrLn report
common inSrc excludes outSrc _ = do
putStrLn $ "Refactoring common blocks in '" ++ inSrc ++ "'"
isDir <- isDirectory inSrc
let rfun = commonElimToModules (takeDirectory outSrc ++ "/")
report <- doRefactorAndCreate rfun inSrc excludes outSrc
putStrLn report
equivalences inSrc excludes outSrc _ = do
putStrLn $ "Refactoring equivalences blocks in '" ++ inSrc ++ "'"
report <- doRefactor (mapM refactorEquivalences) inSrc excludes outSrc
putStrLn report
datatypes inSrc excludes outSrc _ = do
putStrLn $ "Introducing derived data types in '" ++ inSrc ++ "'"
report <- doRefactor dataTypeIntro inSrc excludes outSrc
putStrLn report
optsToUnitOpts :: [Flag] -> IO UnitOpts
optsToUnitOpts = foldM (\ o f -> do
case f of
Literals m -> return $ o { uoLiterals = m }
Debug -> return $ o { uoDebug = True }
IncludeDir d -> do
modFileNames <- filter isModFile `fmap` rGetDirContents' d
assocList <- forM modFileNames $ \ modFileName -> do
eResult <- decodeFileOrFail (d ++ "/" ++ modFileName)
case eResult of
Left (offset, msg) -> do
putStrLn $ modFileName ++ ": Error at offset " ++ show offset ++ ": " ++ msg
return (modFileName, emptyModFile)
Right modFile -> do
putStrLn $ modFileName ++ ": successfully parsed precompiled file."
return (modFileName, modFile)
return $ o { uoModFiles = M.fromList assocList `M.union` uoModFiles o }
_ -> return o
) unitOpts0
getModFiles :: [Flag] -> IO ModFiles
getModFiles = foldM (\ modFiles f -> do
case f of
IncludeDir d -> do
modFileNames <- filter isModFile `fmap` rGetDirContents' d
addedModFiles <- forM modFileNames $ \ modFileName -> do
eResult <- decodeFileOrFail (d ++ "/" ++ modFileName)
case eResult of
Left (offset, msg) -> do
putStrLn $ modFileName ++ ": Error at offset " ++ show offset ++ ": " ++ msg
return emptyModFile
Right modFile -> do
putStrLn $ modFileName ++ ": successfully parsed precompiled file."
return modFile
return $ addedModFiles ++ modFiles
_ -> return modFiles
) emptyModFiles
isModFile = (== modFileSuffix) . fileExt
unitsCheck inSrc excludes _ opt = do
putStrLn $ "Checking units for '" ++ inSrc ++ "'"
uo <- optsToUnitOpts opt
let rfun = concatMap (LU.checkUnits uo)
doAnalysisReportWithModFiles rfun putStrLn inSrc excludes =<< getModFiles opt
unitsInfer inSrc excludes _ opt = do
putStrLn $ "Inferring units for '" ++ inSrc ++ "'"
uo <- optsToUnitOpts opt
let rfun = concatMap (LU.inferUnits uo)
doAnalysisReportWithModFiles rfun putStrLn inSrc excludes =<< getModFiles opt
unitsCompile inSrc excludes outSrc opt = do
putStrLn $ "Compiling units for '" ++ inSrc ++ "'"
uo <- optsToUnitOpts opt
let rfun = LU.compileUnits uo
putStrLn =<< doCreateBinary rfun inSrc excludes outSrc =<< getModFiles opt
unitsSynth inSrc excludes outSrc opt = do
putStrLn $ "Synthesising units for '" ++ inSrc ++ "'"
let marker
| Doxygen `elem` opt = '<'
| Ford `elem` opt = '!'
| otherwise = '='
uo <- optsToUnitOpts opt
let rfun =
mapM (LU.synthesiseUnits uo marker)
report <- doRefactorWithModFiles rfun inSrc excludes outSrc =<< getModFiles opt
putStrLn report
unitsCriticals inSrc excludes _ opt = do
putStrLn $ "Suggesting variables to annotate with unit specifications in '"
++ inSrc ++ "'"
uo <- optsToUnitOpts opt
let rfun = mapM (LU.inferCriticalVariables uo)
doAnalysisReportWithModFiles rfun (putStrLn . fst) inSrc excludes =<< getModFiles opt
stencilsCheck inSrc excludes _ _ = do
putStrLn $ "Checking stencil specs for '" ++ inSrc ++ "'"
let rfun = \f p -> (Stencils.check f p, p)
doAnalysisSummary rfun inSrc excludes Nothing
stencilsInfer inSrc excludes outSrc opt = do
putStrLn $ "Infering stencil specs for '" ++ inSrc ++ "'"
let rfun = Stencils.infer (getOption opt) '='
doAnalysisSummary rfun inSrc excludes (Just outSrc)
stencilsSynth inSrc excludes outSrc opt = do
putStrLn $ "Synthesising stencil specs for '" ++ inSrc ++ "'"
let marker
| Doxygen `elem` opt = '<'
| Ford `elem` opt = '!'
| otherwise = '='
let rfun = Stencils.synth (getOption opt) marker
report <- doRefactor rfun inSrc excludes outSrc
putStrLn report