module Camfort.Specification.Units.Synthesis
(runSynthesis)
where
import Data.Function
import Data.List
import Data.Matrix
import Data.Maybe
import Data.Ratio (numerator, denominator)
import qualified Data.Map.Strict as M
import qualified Data.Set as S
import Data.Generics.Uniplate.Operations
import Control.Monad.State.Strict hiding (gets)
import Control.Monad.Reader
import Control.Monad.Writer.Strict
import Control.Monad
import qualified Language.Fortran.AST as F
import qualified Language.Fortran.Analysis as FA
import qualified Language.Fortran.Analysis.Renaming as FAR
import qualified Language.Fortran.Util.Position as FU
import qualified Camfort.Specification.Units.Parser as P
import Camfort.Analysis.CommentAnnotator
import Camfort.Analysis.Annotations hiding (Unitless)
import Camfort.Specification.Units.Environment
import Camfort.Specification.Units.Monad
import qualified Debug.Trace as D
runSynthesis :: Char -> [(VV, UnitInfo)] -> UnitSolver [(VV, UnitInfo)]
runSynthesis marker vars = do
modifyProgramFileM $ descendBiM (synthBlocks marker vars)
return vars
synthBlocks :: Char -> [(VV, UnitInfo)] -> [F.Block UA] -> UnitSolver [F.Block UA]
synthBlocks marker vars = fmap reverse . foldM (synthBlock marker vars) []
synthBlock :: Char -> [(VV, UnitInfo)] -> [F.Block UA] -> F.Block UA -> UnitSolver [F.Block UA]
synthBlock marker vars bs b@(F.BlStatement a ss@(FU.SrcSpan lp up) _ (F.StDeclaration _ _ _ _ decls)) = do
pf <- usProgramFile `fmap` get
gvSet <- usGivenVarSet `fmap` get
newBs <- fmap catMaybes . forM (universeBi decls) $ \ e -> case e of
e@(F.ExpValue _ _ (F.ValVariable _))
| vname `S.notMember` gvSet
, Just u <- lookup (vname, sname) vars -> do
let newA = a { FA.prevAnnotation = (FA.prevAnnotation a) {
prevAnnotation = (prevAnnotation (FA.prevAnnotation a)) {
refactored = Just lp } } }
let newSS = FU.SrcSpan (lp {FU.posColumn = 0}) (lp {FU.posColumn = 0})
let txt = marker:" " ++ showUnitDecl (e, u)
let space = FU.posColumn lp 1
let newB = F.BlComment newA newSS . insertSpacing space $ commentText pf txt
return $ Just newB
where
vname = FA.varName e
sname = FA.srcName e
(e :: F.Expression UA) -> return Nothing
return (b:reverse newBs ++ bs)
synthBlock _ _ bs b = return (b:bs)
commentText :: F.ProgramFile UA -> String -> String
commentText _ text = "!" ++ text
insertSpacing :: Int -> String -> String
insertSpacing n = (replicate n ' ' ++)
showUnitDecl (e, u) = "unit(" ++ show u ++ ") :: " ++ FA.srcName e