module Language.Clafer.QNameUID (
QName,
FQName,
PQName,
QNameMaps,
UID,
deriveQNameMaps,
getUIDs,
getFQName,
getLPQName,
getQNameUIDTriples
)
where
import Data.Maybe
import Data.List.Split
import qualified Data.Map as Map
import qualified Data.StringMap as SMap
import Language.Clafer.Intermediate.Intclafer
type QName = String
type FQName = String
type FQKey = String
type PQName = String
type FQNameUIDMap = SMap.StringMap UID
type UIDFqNameMap = Map.Map UID FQName
type UIDLpqNameMap = Map.Map UID PQName
data QNameMaps = QNameMaps FQNameUIDMap UIDFqNameMap UIDLpqNameMap
getUIDs :: QNameMaps -> QName -> [UID]
getUIDs (QNameMaps fqNameUIDMap _ _) qName = findUIDsByFQName fqNameUIDMap qName
getFQName :: QNameMaps -> UID -> Maybe FQName
getFQName (QNameMaps _ uidFqNameMap _) uid' = Map.lookup uid' uidFqNameMap
getLPQName :: QNameMaps -> UID -> Maybe PQName
getLPQName (QNameMaps _ _ uidLpqNameMap) uid' = Map.lookup uid' uidLpqNameMap
deriveQNameMaps :: IModule -> QNameMaps
deriveQNameMaps iModule =
let
(fqNameUIDMap, uidFqNameMap) = deriveFQNameUIDMaps iModule
uidLpqNameMap = deriveUidLpqNameMap fqNameUIDMap
in
QNameMaps fqNameUIDMap uidFqNameMap uidLpqNameMap
deriveFQNameUIDMaps :: IModule -> (FQNameUIDMap, UIDFqNameMap)
deriveFQNameUIDMaps iModule = addElements ["::"] (_mDecls iModule) (SMap.empty, Map.empty)
addElements :: [String] -> [IElement] -> (FQNameUIDMap, UIDFqNameMap) -> (FQNameUIDMap, UIDFqNameMap)
addElements path elems maps = foldl (addClafer path) maps elems
addClafer :: [String] -> (FQNameUIDMap, UIDFqNameMap) -> IElement -> (FQNameUIDMap, UIDFqNameMap)
addClafer path (fqNameUIDMap, uidFqNameMap) (IEClafer iClaf) =
let
newPath = (_ident iClaf) : path
fqKey :: FQKey
fqKey = concat newPath
fqName :: FQName
fqName = getQNameFromKey fqKey
fqNameUIDMap' = SMap.insert fqKey (_uid iClaf) fqNameUIDMap
uidFqNameMap' = Map.insert (_uid iClaf) fqName uidFqNameMap
in
addElements ("::" : newPath) (_elements iClaf) (fqNameUIDMap', uidFqNameMap')
addClafer _ maps _ = maps
findUIDsByFQName :: FQNameUIDMap -> FQName -> [ UID ]
findUIDsByFQName fqNameUIDMap fqName@(':':':':_) = SMap.lookup (getFQKey fqName) fqNameUIDMap
findUIDsByFQName fqNameUIDMap fqName = SMap.prefixFind (getFQKey fqName) fqNameUIDMap
reverseOnQualifier :: FQName -> FQName
reverseOnQualifier fqName = concat $ reverse $ split (onSublist "::") fqName
getFQKey :: FQName -> FQKey
getFQKey = reverseOnQualifier
getQNameFromKey :: FQKey -> QName
getQNameFromKey = reverseOnQualifier
deriveUidLpqNameMap :: FQNameUIDMap -> UIDLpqNameMap
deriveUidLpqNameMap fqNameUIDMap =
SMap.foldrWithKey (generateUIDLpqMapEntry fqNameUIDMap) Map.empty fqNameUIDMap
generateUIDLpqMapEntry :: FQNameUIDMap -> SMap.Key -> UID -> UIDLpqNameMap -> UIDLpqNameMap
generateUIDLpqMapEntry fqNameUIDMap fqKey uid' uidLpqNameMap =
Map.insert uid' lpqName uidLpqNameMap
where
fqName :: FQName
fqName = getQNameFromKey fqKey
lpqName :: QName
lpqName = findLeastQualifiedName fqName fqNameUIDMap
findLeastQualifiedName :: String -> FQNameUIDMap -> String
findLeastQualifiedName fqName'@(':':':':pqName) fqNameUIDMap' =
if (length (findUIDsByFQName fqNameUIDMap' pqName) > 1)
then fqName'
else findLeastQualifiedName pqName fqNameUIDMap'
findLeastQualifiedName pqName fqNameUIDMap' =
let
lessQName = concat $ drop 2 $ split (onSublist "::") pqName
in
if (length (findUIDsByFQName fqNameUIDMap' lessQName) > 1)
then pqName
else findLeastQualifiedName lessQName fqNameUIDMap'
getQNameUIDTriples :: QNameMaps -> [(FQName, PQName, UID)]
getQNameUIDTriples qNameMaps@(QNameMaps _ uidFqNameMap _) =
let
uidFqNameList :: [(UID, FQName)]
uidFqNameList = Map.toList uidFqNameMap
in
map (\(uid', fqName) -> (fqName, fromMaybe fqName $ getLPQName qNameMaps uid', uid')) uidFqNameList