clafer-0.3.8: src/Language/Clafer/JSONMetaData.hs
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2014 Michal Antkiewicz <http://gsd.uwaterloo.ca>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-}
-- | Creates JSON outputs for different kinds of metadata.
module Language.Clafer.JSONMetaData (
generateJSONnameUIDMap,
generateJSONScopes,
parseJSONScopes,
writeCfrScopeFile,
readCfrScopeFile
)
where
import Control.Lens hiding (element)
import Data.Aeson.Lens
import qualified Data.List as List
import Data.Maybe
import Data.Json.Builder
import Data.String.Conversions
import qualified Data.Text as T
import System.FilePath
import System.Directory
import Language.Clafer.QNameUID
-- | Generate a JSON list of triples containing a fully-qualified-, least-partially-qualified name, and unique id.
-- | Both the FQNames and UIDs are brittle. LPQNames are the least brittle.
generateJSONnameUIDMap :: QNameMaps -> String
generateJSONnameUIDMap qNameMaps =
prettyPrintJSON $ convertString $ toJsonBS $ foldl generateQNameUIDArrayEntry mempty sortedTriples
where
sortedTriples :: [(FQName, PQName, UID)]
sortedTriples = List.sortBy (\(fqName1, _, _) (fqName2, _, _) -> compare fqName1 fqName2) $ getQNameUIDTriples qNameMaps
generateQNameUIDArrayEntry :: Array -> (FQName, PQName, UID) -> Array
generateQNameUIDArrayEntry array (fqName, lpqName, uid) =
mappend array $ element $ mconcat [
row ("fqName" :: String) fqName,
row ("lpqName" :: String) lpqName,
row ("uid" :: String) uid ]
-- | Generate a JSON list of tuples containing a least-partially-qualified name and a scope
generateJSONScopes :: QNameMaps -> [(UID, Integer)] -> String
generateJSONScopes qNameMaps scopes =
prettyPrintJSON $ convertString $ toJsonBS $ foldl generateLpqNameScopeArrayEntry mempty sortedLpqNameScopeList
where
lpqNameScopeList = map (\(uid, scope) -> (fromMaybe uid $ getLPQName qNameMaps uid, scope)) scopes
sortedLpqNameScopeList :: [(PQName, Integer)]
sortedLpqNameScopeList = List.sortBy (\(lpqName1, _) (lpqName2, _) -> compare lpqName1 lpqName2) lpqNameScopeList
generateLpqNameScopeArrayEntry :: Array -> (PQName, Integer) -> Array
generateLpqNameScopeArrayEntry array (lpqName, scope) =
mappend array $ element $ mconcat [
row ("lpqName" :: String) lpqName,
row ("scope" :: String) scope ]
-- insert a new line after [, {, and ,
prettyPrintJSON :: String -> String
prettyPrintJSON ('[':line) = '[':'\n':(prettyPrintJSON line)
prettyPrintJSON ('{':line) = '{':'\n':(prettyPrintJSON line)
prettyPrintJSON (',':line) = ',':'\n':(prettyPrintJSON line)
-- insert a new line before ], }
prettyPrintJSON (']':line) = '\n':']':(prettyPrintJSON line)
prettyPrintJSON ('}':line) = '\n':'}':(prettyPrintJSON line)
-- just rewrite and continue
prettyPrintJSON (c:line) = c:(prettyPrintJSON line)
prettyPrintJSON "" = ""
-- | given the QNameMaps, parse the JSON scopes and return list of scopes
parseJSONScopes :: QNameMaps -> String -> [ (UID, Integer) ]
parseJSONScopes qNameMaps scopesJSON =
foldl (\uidScopes qScope -> (qNameToUIDs qScope) ++ uidScopes) [] decodedScopes
where
-- QName
decodedScopes :: [ (T.Text, Integer) ]
decodedScopes = scopesJSON ^.. _Array . traverse
. to (\o -> ( o ^?! key "lpqName" . _String
, o ^?! key "scope" . _Integer)
)
-- a QName may resolve to potentially multiple UIDs
qNameToUIDs :: (T.Text, Integer) -> [ (UID, Integer) ]
qNameToUIDs (qName, scope) = if T.null qName
then [ ("", scope) ]
else [ (uid, scope) | uid <- getUIDs qNameMaps $ convertString qName]
-- | Write a .cfr-scope file
writeCfrScopeFile :: [ (UID, Integer) ] -> QNameMaps -> FilePath -> IO ()
writeCfrScopeFile uidScopes qNameMaps modelName = do
let
scopesInJSON = generateJSONScopes qNameMaps uidScopes
writeFile (replaceExtension modelName ".cfr-scope") scopesInJSON
-- | Read a .cfr-scope file
readCfrScopeFile :: QNameMaps -> FilePath -> IO (Maybe [ (UID, Integer) ])
readCfrScopeFile qNameMaps modelName = do
let
cfrScopeFileName = replaceExtension modelName ".cfr-scope"
exists <- doesFileExist cfrScopeFileName
if exists
then do
scopesInJSON <- readFile cfrScopeFileName
return $ Just $ parseJSONScopes qNameMaps scopesInJSON
else return Nothing