-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathParseCLAsLibDefn.hs
226 lines (188 loc) · 8.19 KB
/
ParseCLAsLibDefn.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
{- |
Module : ./CommonLogic/ParseCLAsLibDefn.hs
Copyright : Eugen Kuksa 2011
License : GPLv2 or higher, see LICENSE.txt
Maintainer : eugenk@informatik.uni-bremen.de
Stability : provisional
Portability : non-portable (imports Logic.Logic)
Analyses CommonLogic files.
-}
module CommonLogic.ParseCLAsLibDefn (parseCL_CLIF) where
import Common.Id
import Common.IRI
import Common.LibName
import Common.AS_Annotation as Anno
import Common.AnnoState
import Common.Parsec
import Common.Result
import Common.ResultT
import Driver.Options
import Driver.ReadFn
import Text.ParserCombinators.Parsec
import Logic.Grothendieck
import CommonLogic.AS_CommonLogic as CL
import CommonLogic.Logic_CommonLogic
import qualified CommonLogic.Parse_CLIF as CLIF (basicSpec)
import Syntax.AS_Library
import Syntax.AS_Structured
import Control.Monad (foldM)
import Control.Monad.Trans
import qualified Data.Set as Set
import qualified Data.Map as Map
import Data.List
import System.FilePath
type SpecMap = Map.Map FilePath SpecInfo
type SpecInfo = (BASIC_SPEC, FilePath, Set.Set String, Set.Set FilePath)
-- (spec, topTexts, importedBy)
-- | call for CommonLogic CLIF-parser with recursive inclusion of importations
parseCL_CLIF :: FilePath -> HetcatsOpts -> ResultT IO [LIB_DEFN]
parseCL_CLIF filename opts = do
let dirFile@(dir, _) = splitFileName filename
specMap <- downloadSpec opts Map.empty Set.empty Set.empty False dirFile dir
return $ map convertToLibDefN $ topSortSpecs
$ Map.map (\ (b, f, _, _) ->
(b, f, Set.map (rmSuffix . tokStr) $ directImports b)) specMap
-- call for CommonLogic CLIF-parser for a single file
parseCL_CLIF_contents :: FilePath -> String -> Either ParseError [BASIC_SPEC]
parseCL_CLIF_contents = runParser (many (CLIF.basicSpec Map.empty) << eof)
(emptyAnnos ())
{- maps imports in basic spec to global definition links (extensions) in
development graph -}
convertToLibDefN :: (FilePath, BASIC_SPEC, FilePath) -> LIB_DEFN
convertToLibDefN (fp, spec, realFp) = let
i = filePathToLibId $ rmSuffix fp
in Lib_defn (setFilePath realFp $ iriLibName i)
(makeLogicItem CommonLogic
: map (addDownload False) (importsAsIris spec)
++ [convertToLibItem spec i])
nullRange []
convertToLibItem :: BASIC_SPEC -> IRI -> Anno.Annoted LIB_ITEM
convertToLibItem b i = makeSpecItem i $ createSpec b
importsAsIris :: BASIC_SPEC -> [IRI]
importsAsIris =
map (filePathToLibId . rmSuffix . tokStr) . Set.toList . directImports
createSpec :: BASIC_SPEC -> Anno.Annoted SPEC
createSpec b = addImports (importsAsIris b)
. makeSpec $ G_basic_spec CommonLogic b
specNameL :: [BASIC_SPEC] -> String -> [String]
specNameL bs def = case bs of
[_] -> [def]
_ -> map (specName def) [0 .. (length bs)]
-- returns a unique name for a node
specName :: String -> Int -> String
specName def i = def ++ "_" ++ show i
fileCombine :: FilePath -> FilePath -> FilePath
fileCombine d = (\ s -> case s of
'.' : p : r | isPathSeparator p -> r
_ -> s) . combine d
httpCombine :: FilePath -> FilePath -> FilePath
httpCombine d f = if checkUri f then f else fileCombine d f
collectDownloads :: HetcatsOpts -> String -> SpecMap -> (String, SpecInfo)
-> ResultT IO SpecMap
collectDownloads opts baseDir specMap (n, (b, _, topTexts, importedBy)) = do
let directImps = Set.elems $ Set.map tokStr $ directImports b
newTopTexts = Set.insert n topTexts
newImportedBy = Set.insert n importedBy
foldM (\ sm d -> do
let p@(ddir, _) = splitFileName d
baseDir' = httpCombine baseDir ddir
newDls <- downloadSpec opts sm newTopTexts newImportedBy True
p baseDir'
return (Map.unionWith unify newDls sm)
) specMap directImps -- imports get @n@ as new "importedBy"
justErr :: a -> String -> ResultT IO a
justErr a s = liftR $ plain_error a s nullRange
downloadSpec :: HetcatsOpts -> SpecMap -> Set.Set String -> Set.Set String
-> Bool -> (String, String) -> String -> ResultT IO SpecMap
downloadSpec opts specMap topTexts importedBy isImport dirFile baseDir = do
let fn = rmSuffix $ uncurry httpCombine dirFile
case Map.lookup fn specMap of
Just info@(b, f, t, _)
| isImport && Set.member fn importedBy ->
justErr specMap . intercalate "\n "
$ "unsupported cyclic imports:" : Set.toList importedBy
| t == topTexts
-> return specMap
| otherwise ->
let newInfo = unify info (b, f, topTexts, importedBy)
newSpecMap = Map.insert fn newInfo specMap
in collectDownloads opts baseDir newSpecMap (fn, newInfo)
Nothing -> do
mCont <- lift $ getCLIFContents opts dirFile baseDir
case mCont of
Left err -> justErr specMap $ show err
Right (file, contents) -> do
lift $ putIfVerbose opts 2 $ "Downloaded " ++ file
case parseCL_CLIF_contents fn contents of
Left err -> justErr specMap $ show err
Right bs -> do
let nbs = zip (specNameL bs fn) bs
nbs2 <- mapM (\ (n, b) -> case
map (rmSuffix . tokStr) $ clTexts b of
[txt] -> if txt == fn then return (n, b) else
liftR $ justWarn (if isImport then n else txt, b)
$ "filename " ++ show fn
++ " does not match cl-text " ++ show txt
[] -> liftR $ justWarn (n, b)
$ "missing cl-text in " ++ show fn
ts -> liftR $ justWarn (n, b)
$ "multiple cl-text entries in "
++ show fn ++ "\n" ++ unlines (map show ts)
) nbs
let nbtis = map (\ (n, b) ->
(n, (b, file, topTexts, importedBy))) nbs2
newSpecMap = foldr (\ (n, bti) sm ->
Map.insertWith unify n bti sm
) specMap nbtis
foldM (\ sm nbt -> do
newDls <- collectDownloads opts baseDir sm nbt
return (Map.unionWith unify newDls sm)
) newSpecMap nbtis
unify :: SpecInfo -> SpecInfo -> SpecInfo
unify (_, _, s, p) (a, b, t, q) = (a, b, s `Set.union` t, p `Set.union` q)
{- one could add support for uri fragments/query
(perhaps select a text from the file) -}
getCLIFContents :: HetcatsOpts -> (String, String) -> String
-> IO (Either String (FilePath, String))
getCLIFContents opts dirFile baseDir =
let fn = uncurry httpCombine dirFile
uStr = useCatalogURL opts
$ if checkUri baseDir then httpCombine baseDir fn else fn
in getExtContent opts { libdirs = baseDir : libdirs opts }
[".clif", ".clf"] uStr
-- retrieves all importations from the text
directImports :: BASIC_SPEC -> Set.Set NAME
directImports (CL.Basic_spec items) = Set.unions
$ map (getImports_textMetas . textsFromBasicItems . Anno.item) items
clTexts :: BASIC_SPEC -> [NAME]
clTexts (CL.Basic_spec items) =
concatMap (getClTexts . textsFromBasicItems . Anno.item) items
textsFromBasicItems :: BASIC_ITEMS -> [TEXT_META]
textsFromBasicItems (Axiom_items axs) = map Anno.item axs
getImports_textMetas :: [TEXT_META] -> Set.Set NAME
getImports_textMetas = Set.unions . map (getImports_text . getText)
getClTexts :: [TEXT_META] -> [NAME]
getClTexts = concatMap (getClTextTexts . getText)
getClTextTexts :: TEXT -> [NAME]
getClTextTexts txt = case txt of
Named_text n t _ -> n : getClTextTexts t
_ -> []
getImports_text :: TEXT -> Set.Set NAME
getImports_text txt = case txt of
Text p _ -> Set.fromList $ map impName $ filter isImportation p
Named_text _ t _ -> getImports_text t
isImportation :: PHRASE -> Bool
isImportation ph = case ph of
Importation _ -> True
_ -> False
impName :: PHRASE -> NAME
impName ph = case ph of
Importation (Imp_name n) -> n
_ -> error "CL.impName"
topSortSpecs :: Map.Map FilePath (BASIC_SPEC, FilePath, Set.Set FilePath)
-> [(FilePath, BASIC_SPEC, FilePath)]
topSortSpecs specMap =
let (fm, rm) = Map.partition (\ (_, _, is) -> Set.null is) specMap
in if Map.null fm then [] else
map (\ (n, (b, f, _)) -> (n, b, f)) (Map.toList fm) ++ topSortSpecs
(Map.map (\ (b, f, is) -> (b, f, is Set.\\ Map.keysSet fm)) rm)