module Language.C.Analysis.NameSpaceMap (
NameSpaceMap, nameSpaceMap, nsMapToList,
globalNames,localNames,hasLocalNames,
defGlobal,
enterNewScope, leaveScope,
defLocal,
lookupName,lookupGlobal,lookupInnermostScope,
mergeNameSpace
)
where
import Prelude hiding (lookup)
import qualified Prelude
import qualified Data.Map as Map (empty, insert, lookup, toList, union)
import qualified Data.List as List (unionBy)
import Data.Map (Map)
data NameSpaceMap k v = NsMap (Map k v) [[(k, v)]] globalNames :: (Ord k) => NameSpaceMap k v -> Map k v
globalNames (NsMap g _) = g
hasLocalNames :: NameSpaceMap k v -> Bool
hasLocalNames (NsMap _ l) = not (null l)
localNames :: (Ord k) => NameSpaceMap k v -> [[(k,v)]]
localNames (NsMap _ l) = l
nameSpaceMap :: (Ord k) => NameSpaceMap k v
nameSpaceMap = NsMap Map.empty []
defGlobal :: (Ord k) => NameSpaceMap k a -> k -> a -> (NameSpaceMap k a, Maybe a)
defGlobal (NsMap gs lss) ident def
= (NsMap (Map.insert ident def gs) lss, Map.lookup ident gs)
enterNewScope :: (Ord k) => NameSpaceMap k a -> NameSpaceMap k a
enterNewScope (NsMap gs lss) = NsMap gs ([]:lss)
leaveScope :: (Ord k) => NameSpaceMap k a -> (NameSpaceMap k a, [(k, a)])
leaveScope (NsMap _ []) = error "NsMaps.leaveScope: No local scope!"
leaveScope (NsMap gs (ls:lss)) = (NsMap gs lss, ls)
defLocal :: (Ord k) => NameSpaceMap k a -> k -> a -> (NameSpaceMap k a, Maybe a)
defLocal ns@(NsMap _ []) ident def = defGlobal ns ident def
defLocal (NsMap gs (ls:lss)) ident def =
(NsMap gs (((ident, def):ls):lss),
Prelude.lookup ident ls)
lookupName :: (Ord k) => NameSpaceMap k a -> k -> Maybe a
lookupName ns@(NsMap _ localDefs) ident
= case lookupLocal localDefs of
Nothing -> lookupGlobal ns ident
Just def -> Just def
where
lookupLocal [] = Nothing
lookupLocal (ls:lss) =
case Prelude.lookup ident ls of
Nothing -> lookupLocal lss
Just def -> Just def
lookupGlobal :: (Ord k) => NameSpaceMap k a -> k -> Maybe a
lookupGlobal (NsMap gs _) ident = Map.lookup ident gs
lookupInnermostScope :: (Ord k) => NameSpaceMap k a -> k -> Maybe a
lookupInnermostScope nsm@(NsMap _gs localDefs) ident =
case localDefs of
(ls : _lss) -> Prelude.lookup ident ls
[] -> lookupGlobal nsm ident
nsMapToList :: (Ord k) => NameSpaceMap k a -> [(k, a)]
nsMapToList (NsMap gs lss) = concat lss ++ Map.toList gs
mergeNameSpace :: (Ord k) =>
NameSpaceMap k a
-> NameSpaceMap k a
-> NameSpaceMap k a
mergeNameSpace (NsMap global1 local1) (NsMap global2 local2) =
NsMap (Map.union global1 global2) (localUnion local1 local2)
where localUnion (l1:ls1) (l2:ls2) =
List.unionBy (\p1 p2 -> fst p1 == fst p2) l1 l2 : localUnion ls1 ls2
localUnion [] ls2 = ls2
localUnion ls1 [] = ls1