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 as M
import qualified Data.Set as S
import Data.Generics.Uniplate.Operations
import Data.Label.Monadic hiding (modify)
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 qualified Camfort.Output as O (srcSpanToSrcLocs)
import Camfort.Analysis.Annotations hiding (Unitless)
import Camfort.Specification.Units.Environment
import Camfort.Specification.Units.Monad
import qualified Debug.Trace as D
runSynthesis :: [(String, UnitInfo)] -> UnitSolver [(String, UnitInfo)]
runSynthesis vars = do
modifyProgramFileM $ descendBiM (synthBlocks vars)
return vars
synthBlocks :: [(String, UnitInfo)] -> [F.Block UA] -> UnitSolver [F.Block UA]
synthBlocks vars = fmap reverse . foldM (synthBlock vars) []
synthBlock :: [(String, UnitInfo)] -> [F.Block UA] -> F.Block UA -> UnitSolver [F.Block UA]
synthBlock vars bs b@(F.BlStatement a ss@(FU.SrcSpan lp up) _ (F.StDeclaration _ _ _ _ decls)) = do
pf <- usProgramFile `fmap` get
nMap <- uoNameMap `fmap` ask
gvSet <- usGivenVarSet `fmap` get
newBs <- fmap catMaybes . forM (universeBi decls) $ \ e -> case e of
e@(F.ExpValue _ _ (F.ValVariable _))
| name `S.notMember` gvSet
, Just u <- lookup name vars -> do
let loc = fst $ O.srcSpanToSrcLocs ss
let newA = a { FA.prevAnnotation = (FA.prevAnnotation a) {
prevAnnotation = (prevAnnotation (FA.prevAnnotation a)) {
refactored = Just loc } } }
let newSS = FU.SrcSpan (lp {FU.posColumn = 0}) (lp {FU.posColumn = 0})
let txt = "= " ++ showUnitDecl nMap (e, u)
let space = FU.posColumn lp 1
let newB = F.BlComment newA newSS . insertSpacing space $ commentText pf txt
return $ Just newB
where
name = FA.varName 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 nameMap (e, u) = "unit(" ++ show u ++ ") :: " ++ (v `fromMaybe` M.lookup v nameMap)
where v = FA.varName e