import
Network.HTTP (simpleHTTP, getRequest, getResponseBody)
-- a set of library names to check for cyclic imports
{- | parsing and static analysis for files
Parameters: logic graph, default logic, file name -}
anaSourceFile :: LogicGraph -> HetcatsOpts -> LNS -> LibEnv -> DGraph
-> FilePath -> ResultT IO (LibName, LibEnv)
anaSourceFile = anaSource Nothing
anaSource :: Maybe LibName -- ^ suggested library name
-> LogicGraph -> HetcatsOpts -> LNS -> LibEnv -> DGraph
-> FilePath -> ResultT IO (LibName, LibEnv)
anaSource mln lg opts topLns libenv initDG fname =
let syn = case defSyntax opts of
s -> Just $ simpleIdToIRI $ mkSimpleId s
lgraph = setSyntax syn $ setCurLogic (defLogic opts) lg in ResultT $
if checkUri fname then do
putIfVerbose opts 2 $ "Downloading file " ++ fname
resp <- simpleHTTP (getRequest fname)
input <- getResponseBody resp
anaString mln lgraph opts topLns libenv initDG input fname
fname' <- findFileOfLibName opts fname
return $ fail $ "no file for library '" ++ fname ++ "' found."
if any (`isSuffixOf` file) [envSuffix, prfSuffix] then
return $ fail $ "no matching source file for '" ++ fname ++ "' found."
inputLit <- readEncFile (ioEncoding opts) file
let input = (if unlit opts then
Unlit.unlit else id) inputLit
libStr = if isAbsolute fname
then convertFileToLibStr fname
else dropExtensions fname
Nothing | useLibPos opts ->
Just $ emptyLibName libStr
putIfVerbose opts 2 $ "Reading file " ++ file
if takeExtension file /= ('.' : show TwelfIn)
anaString nLn lgraph opts topLns libenv initDG input file
res <- anaTwelfFile opts file
Just (lname, lenv) -> return $ Result [] $
{- | parsing and static analysis for string (=contents of file)
Parameters: logic graph, default logic, contents of file, filename -}
anaString :: Maybe LibName -- ^ suggested library name
-> LogicGraph -> HetcatsOpts -> LNS -> LibEnv -> DGraph -> String
-> FilePath -> ResultT IO (LibName, LibEnv)
anaString mln lgraph opts topLns libenv initDG input file = do
curDir <- lift getCurrentDirectory -- get full path for parser positions
let realFileName = curDir </> file
posFileName = case mln of
Just gLn | useLibPos opts -> show $ getLibId gLn
_ -> if checkUri file then file else realFileName
Lib_defn pln is ps ans <- readLibDefnAux lgraph opts file posFileName input
let noSuffixFile = rmSuffix file
spN = convertFileToLibStr file
noLibName = null $ show $ getLibId pln
[Annoted (Spec_defn spn gn as qs) rs [] []]
| noLibName && null (iriToStringUnsecure spn)
-> [Annoted (Spec_defn (simpleIdToIRI $ mkSimpleId spN)
ln = setFilePath posFileName
$ if noLibName then fromMaybe (emptyLibName spN) mln else pln
ast = Lib_defn ln nIs ps ans
lift $ putIfVerbose opts 1 $
"Skipping static analysis of library " ++ show ln
ga <- liftR $ addGlobalAnnos emptyGlobalAnnos ans
lift $ writeLibDefn lgraph ga file opts ast
let libstring = show $ getLibId ln
unless (isSuffixOf libstring noSuffixFile) $ lift
$ "### file name '" ++ file ++ "' does not match library name '"
lift $ putIfVerbose opts 1 $ "Analyzing "
++ (if noLibName then "file " ++ file ++ " as " else "")
(lnFinal, ld, ga, lenv) <-
anaLibDefn lgraph opts topLns libenv initDG ast file
Nothing -> error $ "anaString: missing library: " ++ show lnFinal
writeLibDefn lgraph ga file opts ld
(writeFileInfo opts lnFinal file ld dg)
-- lookup or read a library
anaLibFile :: LogicGraph -> HetcatsOpts -> LNS -> LibEnv -> DGraph -> LibName
-> ResultT IO (LibName, LibEnv)
anaLibFile lgraph opts topLns libenv initDG ln =
let lnstr = show ln in case
Map.lookup ln libenv of
analyzing opts $ "from " ++ lnstr
putMessageIORes opts 1 $ "Downloading " ++ lnstr ++ " ..."
res <- anaLibFileOrGetEnv lgraph
(if recurse opts then opts else opts
(
Set.insert ln topLns) libenv initDG ln $ libNameToFile ln
putMessageIORes opts 1 $ "... loaded " ++ lnstr
-- | lookup or read a library
anaLibFileOrGetEnv :: LogicGraph -> HetcatsOpts -> LNS -> LibEnv -> DGraph
-> LibName -> FilePath -> ResultT IO (LibName, LibEnv)
anaLibFileOrGetEnv lgraph opts topLns libenv initDG ln file = ResultT $ do
let envFile = rmSuffix file ++ envSuffix
recent_envFile <- checkRecentEnv opts envFile file
mgc <- readVerbose lgraph opts ln envFile
Nothing -> runResultT $ do
lift $ putIfVerbose opts 1 $ "Deleting " ++ envFile
lift $ removeFile envFile
anaSource (Just ln) lgraph opts topLns libenv initDG file
writeLibDefn lgraph (globalAnnos gc) file opts ld
-- get all DGRefs from DGraph
Result ds mEnv <- runResultT $ foldl
( \ ioLibEnv labOfDG -> let node = snd labOfDG in
let ln2 = dgn_libname node
else fmap snd $ anaLibFile lgraph
opts topLns p_libEnv initDG ln2
return $ Result ds $ fmap
( \ rEnv -> (ln, rEnv)) mEnv
$ anaSource (Just ln) lgraph opts topLns libenv initDG file
Parameters: logic graph, default logic, opts, library env, LIB_DEFN.
Call this function as follows:
> do Result diags res <- runResultT (anaLibDefn ...)
> mapM_ (putStrLn . show) diags
anaLibDefn :: LogicGraph -> HetcatsOpts -> LNS -> LibEnv -> DGraph -> LIB_DEFN
-> FilePath -> ResultT IO (LibName, LIB_DEFN, GlobalAnnos, LibEnv)
anaLibDefn lgraph opts topLns libenv dg (Lib_defn ln alibItems pos ans) file
let libStr = show (getLibId ln)
isDOLlib = elem ':' libStr
gannos <- showDiags1 opts $ liftR $ addGlobalAnnos
(defPrefixGlobalAnnos $ if isDOLlib then file else libStr) ans
(libItems', dg', libenv', _, _) <- foldM (anaLibItemAux opts topLns ln)
([], dg { globalAnnos = gannos }, libenv
let dg1 = computeDGraphTheories libenv' $ markFree libenv' $
(zipWith replaceAnnoted (reverse libItems') alibItems) pos ans
dg2 = dg1 { optLibDefn = Just newLD }
return (ln, newLD, globalAnnos dg2,
Map.insert ln dg2 libenv')
defPrefixGlobalAnnos :: FilePath -> GlobalAnnos
defPrefixGlobalAnnos file = emptyGlobalAnnos
$ fromMaybe nullIRI $ parseIRIReference $ file ++ "#" }
anaLibItemAux :: HetcatsOpts -> LNS -> LibName
-> ([LIB_ITEM], DGraph, LibEnv, LogicGraph, ExpOverrides) -> LIB_ITEM
-> ResultT IO ([LIB_ITEM], DGraph, LibEnv, LogicGraph, ExpOverrides)
anaLibItemAux opts topLns ln q@(libItems', dg1, libenv1, lg, eo) libItem = let
currLog = currentLogic lg
newOpts = if elem currLog ["DMU", "Framework"] then
opts { defLogic = currLog } else opts
res2@(Result diags2 res) <- runResultT
$ anaLibItem lg newOpts topLns ln libenv1 dg1 eo libItem
runResultT $ showDiags1 opts (liftR res2)
Just (libItem', dg1', libenv1', newLG, eo') ->
Just (libItem' : libItems', dg1', libenv1', newLG, eo')
if outputToStdout opts then
fail "Stopped due to errors"
else runResultT $ liftR $ Result [] mRes
else runResultT $ liftR $ Result diags2 mRes
putMessageIORes :: HetcatsOpts -> Int -> String -> ResultT IO ()
putMessageIORes opts i msg =
then lift $ putIfVerbose opts i msg
else liftR $ message () msg
analyzing :: HetcatsOpts -> String -> ResultT IO ()
analyzing opts = putMessageIORes opts 1 . ("Analyzing " ++)
alreadyDefined :: String -> String
alreadyDefined str = "Name " ++ str ++ " already defined"
-- | analyze a GENERICITY
anaGenericity :: LogicGraph -> LibName -> DGraph -> HetcatsOpts
-> ExpOverrides -> NodeName -> GENERICITY
-> Result (GENERICITY, GenSig, DGraph)
anaGenericity lg ln dg opts eo name
gen@(Genericity (Params psps) (Imported isps) pos) =
let ms = currentBaseTheory dg in
adjustPos pos $ case psps of
[] -> do -- no parameter ...
unless (null isps) $ plain_error ()
"Parameterless specifications must not have imports" pos
l <- lookupCurrentLogic "GENERICITY" lg
return (gen, GenSig (EmptyNode l) []
$ maybe (EmptyNode l) JustNode ms, dg)
l <- lookupCurrentLogic "IMPORTS" lg
let baseNode = maybe (EmptyNode l) JustNode ms
(imps', nsigI, dg') <- case isps of
[] -> return ([], baseNode, dg)
(is', _, nsig', dgI) <- anaUnion False lg ln dg baseNode
(extName "Imports" name) opts eo isps
return (is', JustNode nsig', dgI)
(ps', nsigPs, ns, dg'') <- anaUnion False lg ln dg' nsigI
(extName "Parameters" name) opts eo psps
return (Genericity (Params ps') (Imported imps') pos,
GenSig nsigI nsigPs $ JustNode ns, dg'')
anaLibItem :: LogicGraph -> HetcatsOpts -> LNS -> LibName -> LibEnv -> DGraph
-> ExpOverrides -> LIB_ITEM
-> ResultT IO (LIB_ITEM, DGraph, LibEnv, LogicGraph, ExpOverrides)
anaLibItem lg opts topLns currLn libenv dg eo itm =
Spec_defn spn2 gen asp pos -> let
spn' = if null (iriToStringUnsecure spn2) then
simpleIdToIRI $ mkSimpleId "Spec" else spn2
in case expCurie (globalAnnos dg) eo spn' of
Nothing -> liftR $ prefixErrorIRI spn'
let spstr = iriToStringUnsecure spn
analyzing opts $ "spec " ++ spstr
(gen', gsig@(GenSig _ _args allparams), dg') <-
liftR $ anaGenericity lg currLn dg opts eo nName gen
(sanno1, impliesA) <- liftR $ getSpecAnnos pos asp
when impliesA $ liftR $ plain_error ()
"unexpected initial %implies in spec-defn" pos
liftR (anaSpecTop sanno1 True lg currLn dg'
allparams nName opts eo (item asp))
let libItem' = Spec_defn spn gen' (replaceAnnoted sp' asp) pos
then liftR $ plain_error (libItem', dg'', libenv, lg, eo)
(alreadyDefined spstr) pos
-- let (_n, dg''') = addSpecNodeRT dg'' (UnitSig args body) $ show spn
$ ExtGenSig gsig body) genv }
View_defn vn' gen vt gsis pos -> case expCurie (globalAnnos dg) eo vn' of
Nothing -> liftR $ prefixErrorIRI vn'
analyzing opts $ "view " ++ iriToStringUnsecure vn
liftR $ anaViewDefn lg currLn libenv dg opts eo vn gen vt gsis pos
Arch_spec_defn asn' asp pos -> case expCurie (globalAnnos dg) eo asn' of
Nothing -> liftR $ prefixErrorIRI asn'
let asstr = iriToStringUnsecure asn
analyzing opts $ "arch spec " ++ asstr
(_, _, diag, archSig, dg', asp') <- liftR $ anaArchSpec lg currLn dg
opts eo emptyExtStUnitCtx Nothing $ item asp
let asd' = Arch_spec_defn asn (replaceAnnoted asp' asp) pos
then liftR $ plain_error (asd', dg', libenv, lg, eo)
(alreadyDefined asstr) pos
let dg'' = updateNodeNameRT dg'
(refSource $ getPointerFromRef archSig) $ show asn
dg3 = dg'' { archSpecDiags =
(ArchOrRefEntry True archSig) genv }
Unit_spec_defn usn' usp pos -> case expCurie (globalAnnos dg) eo usn' of
Nothing -> liftR $ prefixErrorIRI usn'
let usstr = iriToStringUnsecure usn
analyzing opts $ "unit spec " ++ usstr
l <- lookupCurrentLogic "Unit_spec_defn" lg
liftR $ anaUnitSpec lg currLn dg opts eo (EmptyNode l) Nothing usp
unitSig <- liftR $ getUnitSigFromRef rSig
let usd' = Unit_spec_defn usn usp' pos
then liftR $ plain_error (itm, dg', libenv, lg, eo)
(alreadyDefined usstr) pos
{ globalEnv =
Map.insert usn (UnitEntry unitSig) genv },
Ref_spec_defn rn' rsp pos -> case expCurie (globalAnnos dg) eo rn' of
Nothing -> liftR $ prefixErrorIRI rn'
let rnstr = iriToStringUnsecure rn
l <- lookupCurrentLogic "Ref_spec_defn" lg
(_, _, _, rsig, dg', rsp') <- liftR $ anaRefSpec lg currLn dg opts eo
(EmptyNode l) rn emptyExtStUnitCtx Nothing rsp
analyzing opts $ "ref spec " ++ rnstr
let rsd' = Ref_spec_defn rn rsp' pos
then liftR $ plain_error (itm, dg', libenv, lg, eo)
(alreadyDefined rnstr) pos
{ globalEnv =
Map.insert rn (ArchOrRefEntry False rsig) genv }
Logic_decl logN pos -> do
putMessageIORes opts 1 . show $ prettyLG lg itm
$ adjustPos pos $ anaSublogic opts logN currLn dg libenv lg
return (itm, dg { currentBaseTheory = Nothing }, libenv, newLg, eo)
Just (s, (libName, refDG, (_, lbl))) -> do
let dg2 = if libName /= currLn then
let (s2, (genv, newDG)) = refExtsigAndInsert libenv libName refDG
(globalEnv dg, dg) (getName $ dgn_name lbl) s
in newDG { globalEnv = genv
, currentBaseTheory = Just $ extGenBody s2 }
else dg { currentBaseTheory = Just $ extGenBody s }
return (itm, dg2, libenv, newLg, eo)
Download_items ln items pos ->
liftR $ mkError "illegal cyclic library import"
(ln', libenv') <- anaLibFile lg opts topLns libenv
(cpIndexMaps dg emptyDG) ln
(shows ln " does not match internal name " ++ shows ln' "")
Nothing -> error $ "Internal error: did not find library "
++ show ln' ++ " available: " ++ show (
Map.keys libenv')
let dg0 = cpIndexMaps dg' dg
(realItems, errs, origItems) = case items of
let (ims, warns) = foldr (\ im@(ItemNameMap i mi)
(is, ws) -> if Just i == mi then
(ItemNameMap i Nothing : is
, warning () (show i ++ " item no renamed")
else (im : is, ws)) ([], []) rawIms
in (ims, warns, itemNameMapsToIRIs ims)
UniqueItem i -> case
Map.keys $ globalEnv dg' of
[j] -> case expCurie (globalAnnos dg) eo i of
Nothing -> ([], [prefixErrorIRI i], [i])
Just expI -> case expCurie (globalAnnos dg) eo j of
Nothing -> ([], [prefixErrorIRI j], [i, j])
([ItemNameMap expJ (Just expI)], [], [i, j])
, [ mkError "non-unique name within imported library"
additionalEo =
Map.fromList $ map (\ o -> (o, fn)) origItems
dg1 <- liftR $ anaItemNamesOrMaps libenv' ln' dg' dg0 realItems
return (itm, dg1, libenv', lg, eo')
Newlogic_defn ld _ -> ResultT $ do
return $ Result [] $ Just (itm, dg', libenv, lg, eo)
Newcomorphism_defn com _ -> ResultT $ do
dg' <- anaComorphismDef com dg
return $ Result [] $ Just (itm, dg', libenv, lg, eo)
_ -> return (itm, dg, libenv, lg, eo)
-- the first DGraph dg' is that of the imported library
anaItemNamesOrMaps :: LibEnv -> LibName -> DGraph -> DGraph
-> [ItemNameMap] -> Result DGraph
anaItemNamesOrMaps libenv' ln refDG dg items = do
(anaItemNameOrMap libenv' ln refDG) (globalEnv dg, dg) items
gannos'' <- mergeGlobalAnnos (globalAnnos refDG) $ globalAnnos dg
-- | analyse genericity and view type and construct gmorphism
anaViewDefn :: LogicGraph -> LibName -> LibEnv -> DGraph -> HetcatsOpts
-> ExpOverrides -> IRI -> GENERICITY -> VIEW_TYPE
-> Result (LIB_ITEM, DGraph, LibEnv, LogicGraph, ExpOverrides)
anaViewDefn lg ln libenv dg opts eo vn gen vt gsis pos = do
(gen', gsig@(GenSig _ _ allparams), dg') <-
anaGenericity lg ln dg opts eo vName gen
(vt', (src@(NodeSig nodeS gsigmaS)
, tar@(NodeSig nodeT gsigmaT@(G_sign lidT _ _))), dg'') <-
anaViewType lg ln dg' allparams opts eo vName vt
let genv = globalEnv dg''
then plain_error (View_defn vn gen' vt' gsis pos, dg'', libenv, lg, eo)
(alreadyDefined $ iriToStringUnsecure vn) pos
let (tsis, hsis) = partitionGmaps gsis
(gsigmaS', tmor) <- if null tsis then do
(gsigmaS', imor) <- gSigCoerce lg gsigmaS (Logic lidT)
tmor <- gEmbedComorphism imor gsigmaS
mor <- anaRenaming lg allparams gsigmaS opts (Renaming tsis pos)
(gsigmaS', imor) <- gSigCoerce lg gsigmaS'' (Logic lidT)
tmor <- gEmbedComorphism imor gsigmaS''
emor <- fmap gEmbed $ anaGmaps lg opts pos gsigmaS' gsigmaT hsis
let vsig = ExtViewSig src gmor $ ExtGenSig gsig tar
voidView = nodeS == nodeT && isInclusion gmor
when voidView $ warning ()
("identity mapping of source to same target for view: " ++
iriToStringUnsecure vn) pos
return (View_defn vn gen' vt' gsis pos,
(if voidView then dg'' else insLink dg'' gmor globalThm
(DGLinkView vn $ Fitted gsis) nodeS nodeT)
-- 'LeftOpen' for conserv correct?
{ globalEnv =
Map.insert vn (ViewOrStructEntry True vsig) genv }
The first three arguments give the global context
The AnyLogic is the current logic
The NodeSig is the signature of the parameter of the view
flag, whether just the structure shall be analysed -}
anaViewType :: LogicGraph -> LibName -> DGraph -> MaybeNode -> HetcatsOpts
-> NodeName -> VIEW_TYPE -> Result (VIEW_TYPE, (NodeSig, NodeSig), DGraph)
anaViewType lg ln dg parSig opts eo name (View_type aspSrc aspTar pos) = do
l <- lookupCurrentLogic "VIEW_TYPE" lg
(spSrc', srcNsig, dg') <- adjustPos pos $ anaSpec False lg ln dg (EmptyNode l)
(extName "Source" name) opts eo (item aspSrc)
(spTar', tarNsig, dg'') <- adjustPos pos $ anaSpec True lg ln dg' parSig
(extName "Target" name) opts eo (item aspTar)
return (View_type (replaceAnnoted spSrc' aspSrc)
(replaceAnnoted spTar' aspTar)
(srcNsig, tarNsig), dg'')
anaItemNameOrMap :: LibEnv -> LibName -> DGraph -> (GlobalEnv, DGraph)
-> ItemNameMap -> Result (GlobalEnv, DGraph)
anaItemNameOrMap libenv ln refDG res (ItemNameMap old m) =
anaItemNameOrMap1 libenv ln refDG res (old, fromMaybe old m)
-- | Auxiliary function for not yet implemented features
anaErr f = error $ "*** Analysis of " ++ f ++ " is not yet implemented!"
anaItemNameOrMap1 :: LibEnv -> LibName -> DGraph -> (GlobalEnv, DGraph)
-> (IRI, IRI) -> Result (GlobalEnv, DGraph)
anaItemNameOrMap1 libenv ln refDG (genv, dg) (old, new) = do
entry <- maybe (notFoundError "item" old) return
$ lookupGlobalEnvDG old refDG
maybeToResult (iriPos new) (iriToStringUnsecure new ++ " already used")
return $ snd $ refExtsigAndInsert libenv ln refDG (genv, dg) new extsig
ViewOrStructEntry b vsig ->
let (dg1, vsig1) = refViewsig libenv ln refDG dg (makeName new) vsig
genv1 =
Map.insert new (ViewOrStructEntry b vsig1) genv
UnitEntry _usig -> anaErr "unit spec download"
ArchOrRefEntry b _rsig -> anaErr $ (if b then "arch" else "ref")
refNodesig :: LibEnv -> LibName -> DGraph -> DGraph -> (NodeName, NodeSig)
refNodesig libenv refln refDG dg
(name, NodeSig refn sigma@(G_sign lid sig ind)) =
lookupRefNode libenv refln refDG refn
refInfo = newRefInfo ln n
new = newInfoNodeLab name refInfo
$ noSensGTheory lid sig ind
nodeCont = new { globalTheory = globalTheory lbl }
in case lookupInAllRefNodesDG refInfo dg of
Just existNode -> (dg, NodeSig existNode sigma)
( insNodeDG (node, nodeCont) dg
refNodesigs :: LibEnv -> LibName -> DGraph -> DGraph -> [(NodeName, NodeSig)]
refNodesigs libenv ln = mapAccumR . refNodesig libenv ln
refExtsigAndInsert :: LibEnv -> LibName -> DGraph -> (GlobalEnv, DGraph)
-> IRI -> ExtGenSig -> (ExtGenSig, (GlobalEnv, DGraph))
refExtsigAndInsert libenv ln refDG (genv, dg) new extsig =
let (dg1, extsig1) = refExtsig libenv ln refDG dg (makeName new) extsig
in (extsig1, (genv1, dg1))
refExtsig :: LibEnv -> LibName -> DGraph -> DGraph -> NodeName -> ExtGenSig
refExtsig libenv ln refDG dg name
(ExtGenSig (GenSig imps params gsigmaP) body) = let
pName = extName "Parameters" name
(dg1, imps1) = case imps of
EmptyNode _ -> (dg, imps)
(dg0, nns) = refNodesig libenv ln refDG dg (extName "Imports" name, ns)
(dg2, params1) = refNodesigs libenv ln refDG dg1
$ snd $ foldr (\ p (n, l) -> let nn = inc n in
(nn, (nn, p) : l)) (pName, []) params
(dg3, gsigmaP1) = case gsigmaP of
EmptyNode _ -> (dg, gsigmaP)
(dg0, nns) = refNodesig libenv ln refDG dg2 (pName, ns)
(dg4, body1) = refNodesig libenv ln refDG dg3 (name, body)
in (dg4, ExtGenSig (GenSig imps1 params1 gsigmaP1) body1)
refViewsig :: LibEnv -> LibName -> DGraph -> DGraph -> NodeName -> ExtViewSig
refViewsig libenv ln refDG dg name (ExtViewSig src mor extsig) = let
(dg1, src1) = refNodesig libenv ln refDG dg (extName "Source" name, src)
(dg2, extsig1) = refExtsig libenv ln refDG dg1 (extName "Target" name) extsig
in (dg2, ExtViewSig src1 mor extsig1)
itemNameMapsToIRIs :: [ItemNameMap] -> [IRI]
itemNameMapsToIRIs = concatMap (\ (ItemNameMap i mi) -> [i | isNothing mi])