module Camfort.Specification.Units.Monad
( UA, VV, UnitSolver, UnitOpts(..), unitOpts0, UnitLogs, UnitState(..), LiteralsOpt(..), UnitException
, whenDebug, modifyVarUnitMap, modifyGivenVarSet, modifyUnitAliasMap
, VarUnitMap, GivenVarSet, UnitAliasMap, TemplateMap, CallIdMap
, modifyTemplateMap, modifyProgramFile, modifyProgramFileM, modifyCallIdRemapM
, runUnitSolver, evalUnitSolver, execUnitSolver )
where
import Control.Monad.RWS.Strict
import Control.Monad.Trans.Except
import Data.Char (toLower)
import Data.Data (Data)
import Data.List (find, isPrefixOf)
import qualified Data.Map.Strict as M
import qualified Data.IntMap.Strict as IM
import qualified Data.Set as S
import qualified Language.Fortran.Analysis as FA
import qualified Language.Fortran.Analysis.Renaming as FAR
import qualified Language.Fortran.AST as F
import Camfort.Specification.Units.Environment (UnitInfo, UnitAnnotation, Constraints(..), VV)
import Camfort.Analysis.Annotations (Annotation, A, UA)
type UnitSolver a = ExceptT UnitException (RWS UnitOpts UnitLogs UnitState) a
type UnitException = ()
data LiteralsOpt
= LitPoly
| LitUnitless
| LitMixed
deriving (Show, Eq, Ord, Data)
instance Read LiteralsOpt where
readsPrec _ s = case find ((`isPrefixOf` map toLower s) . fst) ms of
Just (str, con) -> [(con, drop (length str) s)]
Nothing -> []
where
ms = [ ("poly", LitPoly), ("unitless", LitUnitless), ("mixed", LitMixed)
, ("litpoly", LitPoly), ("litunitless", LitUnitless), ("litmixed", LitMixed) ]
data UnitOpts = UnitOpts
{ uoDebug :: Bool
, uoLiterals :: LiteralsOpt
, uoNameMap :: FAR.NameMap
}
deriving (Show, Read, Data, Eq, Ord)
unitOpts0 :: UnitOpts
unitOpts0 = UnitOpts False LitMixed M.empty
whenDebug :: UnitSolver () -> UnitSolver ()
whenDebug m = fmap uoDebug ask >>= \ d -> when d m
type UnitLogs = String
type VarUnitMap = M.Map VV UnitInfo
type GivenVarSet = S.Set F.Name
type UnitAliasMap = M.Map String UnitInfo
type TemplateMap = M.Map F.Name Constraints
type CallIdMap = IM.IntMap Int
data UnitState = UnitState
{ usProgramFile :: F.ProgramFile UA
, usVarUnitMap :: VarUnitMap
, usGivenVarSet :: GivenVarSet
, usUnitAliasMap :: UnitAliasMap
, usTemplateMap :: TemplateMap
, usLitNums :: Int
, usCallIds :: Int
, usCallIdRemap :: CallIdMap
, usConstraints :: Constraints }
deriving (Show, Data)
unitState0 pf = UnitState { usProgramFile = pf
, usVarUnitMap = M.empty
, usGivenVarSet = S.empty
, usUnitAliasMap = M.empty
, usTemplateMap = M.empty
, usLitNums = 0
, usCallIds = 0
, usCallIdRemap = IM.empty
, usConstraints = [] }
modifyVarUnitMap :: (VarUnitMap -> VarUnitMap) -> UnitSolver ()
modifyVarUnitMap f = modify (\ s -> s { usVarUnitMap = f (usVarUnitMap s) })
modifyGivenVarSet :: (GivenVarSet -> GivenVarSet) -> UnitSolver ()
modifyGivenVarSet f = modify (\ s -> s { usGivenVarSet = f (usGivenVarSet s) })
modifyUnitAliasMap :: (UnitAliasMap -> UnitAliasMap) -> UnitSolver ()
modifyUnitAliasMap f = modify (\ s -> s { usUnitAliasMap = f (usUnitAliasMap s) })
modifyTemplateMap :: (TemplateMap -> TemplateMap) -> UnitSolver ()
modifyTemplateMap f = modify (\ s -> s { usTemplateMap = f (usTemplateMap s) })
modifyProgramFile :: (F.ProgramFile UA -> F.ProgramFile UA) -> UnitSolver ()
modifyProgramFile f = modify (\ s -> s { usProgramFile = f (usProgramFile s) })
modifyProgramFileM :: (F.ProgramFile UA -> UnitSolver (F.ProgramFile UA)) -> UnitSolver ()
modifyProgramFileM f = do
pf <- fmap usProgramFile get
pf' <- f pf
modify (\ s -> s { usProgramFile = pf' })
modifyCallIdRemapM :: (CallIdMap -> UnitSolver (a, CallIdMap)) -> UnitSolver a
modifyCallIdRemapM f = do
idMap <- gets usCallIdRemap
(x, idMap') <- f idMap
modify (\ s -> s { usCallIdRemap = idMap' })
return x
runUnitSolver :: UnitOpts -> F.ProgramFile UA -> UnitSolver a -> (Either UnitException a, UnitState, UnitLogs)
runUnitSolver o pf m = runRWS (runExceptT m) o (unitState0 pf)
evalUnitSolver :: UnitOpts -> F.ProgramFile UA -> UnitSolver a -> (Either UnitException a, UnitLogs)
evalUnitSolver o pf m = (ea, l) where (ea, _, l) = runUnitSolver o pf m
execUnitSolver :: UnitOpts -> F.ProgramFile UA -> UnitSolver a -> Either UnitException (UnitState, UnitLogs)
execUnitSolver o pf m = case runUnitSolver o pf m of
(Left e, _, _) -> Left e
(Right _, s, l) -> Right (s, l)