HaRe-0.6: tools/property/pfe/PfePropCmds.hs
module PfePropCmds where
import Prelude hiding (writeFile,print,readFile,readIO)
import Monad(when)
import List(sort,isPrefixOf)
import Maybe(fromJust,mapMaybe)
import Sets
import PFE0(pput,allModules,preparseModule,findFile,moduleInfoPath,getSubGraph)
import PFE3(parseModule) --parseSourceFile,
--import PFE2(analyzeModules',pfe2info0)
import PfeParse(moduleArgs,moduleArg,qualId,parseQualId) --,just
import PFE_Certs(assertions) --certDir,certsDir,certModuleDir,certDatestampPath
import PfeDepCmds(depgraph,tdepgraph,ppOrig,depGraph)
import PrettyPrint
import AbstractIO
import DirUtils(optCreateDirectory)
--import FileUtils(updateFile)
import MUtils
import PfeParse
import HsModule
import HsModulePretty
import HsModuleMaps(seqEntSpec,mapDecls,mapModMN)
import HsIdent(getHSName)
import ToQC(moduleToQC)
import HasBaseName(getBaseName)
import NameMaps(mapNames)
import PFEdeps(tdepModules',tdefinedNames,isDefaultDecl,isInstDecl,splitDecls)
import SimpleGraphs(reachable)
--import DefinedNames(definedNames)
import TiNames(topName)
import TiClasses(filterDefs)
import TypedIds(IdTy(Assertion))
pfePropCmds =
[--("certscan",(moduleArgs certscan,"update certificate templates for assertions")),
("assertions",(moduleArgs assertionNames,"list names of named assertion")),
("asig", (sequentArg asig,"write an assertion signature to stdout")),
("tasig", (sequentArg tasig,"write an assertion signature to stdout")),
("adiff", (diffArg adiff,"compare an assertion signature to a file")),
("tadiff", (diffArg tadiff,"compare an assertion signature to a file")),
("qc", (moduleArg toQC,"translate to QuickCheck")),
("slice", (qualId slice,"extract a slice (needed part) of the program")),
("pqc", (qualId prunedToQC,"pruned translation to QuickCheck")),
("qcslice", (qualId qcslice,"translate a slice to QuickCheck"))]
diffArg f = args ("<path> "++sequentSyntax) (f @@ parseDiffArg)
parseDiffArg [] = fail "Was expecting a path and a sequent"
parseDiffArg (path:sequent) = (,) path # parseSequent sequent
sequentArg f = args sequentSyntax (f @@ parseSequent)
sequentSyntax = "<M.A> [ .. | <M1.A1 ... Mn.An> ]"
parseSequent [] = fail "At least a conclusion is required"
parseSequent (conc:hyps) = (,) # parseQualId conc <# parseHyps hyps
where
parseHyps [".."] = return Nothing -- everything
parseHyps args = Just # mapM parseQualId args
asig = print @@ assertionSignature
tasig = print @@ tassertionSignature
assertionSignature = assertionSignature' depgraph
tassertionSignature = assertionSignature' tdepgraph
assertionSignature' depgr (qid,_) =
do (deps,(g,ids,used)) <- depgr [qid]
return $ sort [(n,h)|n<-used,(m,(t,ds))<-deps,(dns,(_,h))<-ds,n `elem` dns]
adiff (path,sequent) =
do old <- readIO =<< readFile path
new <- assertionSignature sequent
signatureDiff old new
tadiff (path,sequent) =
do old <- readIO =<< readFile path
new <- tassertionSignature sequent
signatureDiff old new
signatureDiff [] [] = return ()
signatureDiff ns [] = pput $ "No longer depends on:"<+>ppOrigs (map fst ns)
signatureDiff [] ns = pput $ "New dependencies:"<+>ppOrigs (map fst ns)
signatureDiff allold@((n1,h1):old) allnew@((n2,h2):new) =
case compare n1 n2 of
LT -> do pput $ "No longer depends on:"<+>n1
signatureDiff old allnew
GT -> do pput $ "New dependency:"<+>ppOrig n2
signatureDiff allold new
EQ -> do when (h1/=h2) $ pput $ "Changes have been made to:"<+>ppOrig n1
-- <+>parens (h1<>"/="<>h2) -- debug
signatureDiff old new
ppOrigs = ppiFSeq . map ppOrig
assertionNames optms =
do ms <- if null optms then allModules else return optms
mapM_ assertions1 ms
where
assertions1 m =
mapM_ (pput. (m<+>)) =<< (map fst . assertions # preparseModule m)
toQC = pputModuleToQC @@ parseModule
--bnParseModule m = apSnd baseNames # parseModule m
pputModuleToQC = pput . bnModuleToQC
bnModuleToQC = moduleToQC . apSnd baseNames
baseNames = mapModMN getBaseName . mapNames getBaseName
prunedToQC q@(m,n) =
do (t,deps) <- fromJust . lookup m # tdepModules' (Just [m])
let g = depGraph [(d,fs)|(ds,(fs,hash))<-deps,d<-ds]
needed = reachable g [topName Nothing m n Assertion]
isNeeded = any (`elem` needed) . map getHSName . tdefinedNames True m
keepNeeded = mapDecls (filterDefs isNeeded)
pputModuleToQC . apSnd keepNeeded =<< parseModule m
slice = tslice' snd
qcslice = slice' bnModuleToQC
slice' = slice'' True depgraph
tslice' = slice'' False tdepgraph
slice'' allInst depgraph trans q@(m,n) =
do ms <- map (fst.snd) # getSubGraph (Just [m])
(_,(_,_,used)) <- depgraph [q]
let needed = mkSet used
optCreateDirectory "slice"
mapM_ (writeModuleSlice allInst trans needed) ms
writeModuleSlice allInst trans needed m =
unlessM (isPrefixOf "hi/libs/" # findFile m) $ -- skip Prelude & std libs
do let path = "slice/"++moduleInfoPath m++".hs" -- !!!
pput (m<+>"in"<+>path)
writeFile path.pp.
trans.apSnd (sliceModule needed isNeeded.mapDecls splitDecls)
=<< parseModule m
where
isNeeded d = isDefaultDecl d || allInst && isInstDecl d || isNeeded' d
isNeeded' = any (`elementOf` needed) . map getHSName . tdefinedNames allInst m
sliceModule needed isNeeded (HsModule s m es is ds) =
HsModule s m (fmap sliceExports es) (sliceImports is) (sliceDecls ds)
where
sliceDecls = filterDefs isNeeded
sliceExports = mapMaybe sliceExport
sliceImports = map sliceImport
sliceImport (HsImportDecl s m q as optspecs) =
HsImportDecl s m q as $ fmap (apSnd sliceEnts) optspecs
sliceExport e =
case e of
ModuleE m -> Just e
EntE ent -> EntE # sliceEnt ent
sliceEnts = mapMaybe sliceEnt
sliceEnt e =
case e of
ListSubs i is -> ListSubs # keep i <# return is
_ -> seqEntSpec (fmap keep e)
keep n = if n `elementOf` needed
then Just n
else Nothing
{-
certscan ms =
do info <- analyzeModules' pfe2info0 (just ms)
optCreateDirectory certsDir
mapM_ (updateModuleAssertions info) =<< getCurrentModuleGraph
where
updateModuleAssertions info (src,(m,_)) =
do srct <- getModificationTime src
let stampfile = certDatestampPath m
optct <- getModificationTimeMaybe stampfile
when (srct `newerThan` optct) $
do optCreateDirectory (certModuleDir m)
scan
writeFile stampfile ""
where
scan =
mapM_ updAssertionCert.assertions.snd =<<parseSourceFile info src
updAssertionCert (n,pa) =
do let dir=certDir m (pp n)
optCreateDirectory dir
unchanged <- updateFile (dir++"/assert.txt") (pp pa)
unless unchanged $ epput $ "Updated:"<+>m<>"."<>n
-}