packages feed

lhc-0.6.20090126: src/Name/Name.hs

module Name.Name(
    NameType(..),
    Name(..),
    nameName,
    nameType,
    getModule,
    toUnqualified,
    qualifyName,
    ToName(..),
    fromTypishHsName,
    fromValishHsName,
    parseName,
    ffiExportName,
    isConstructorLike,
--    toId,
--    fromId,
    Module,
    isTypeNamespace,
    isValNamespace,
    mainModule,
    nameParts,
    mapName,
    setModule
    ) where

import Data.Char
import Data.Typeable

import StringTable.Atom
import Data.Binary
import C.FFI
import Doc.DocLike
import Doc.PPrint
import GenUtil
import FrontEnd.HsSyn

import Data.Word
import Data.ByteString (ByteString)

import Debug.Trace

data NameType =
    TypeConstructor
    | DataConstructor
    | ClassName
    | TypeVal
    | Val
    | SortName
    | FieldLabel
    | RawType
    deriving(Ord,Eq,Enum,Read,Show)


data Name = Name { nameAtom   :: Atom
                 , nameHash   :: Word32
                 , nameType   :: NameType
                 , nameModule :: Maybe String
                 , nameIdent  :: String
                 }
    deriving(Typeable) --,Eq,Binary,ToAtom,FromAtom)

nameString :: Name -> ByteString
nameString = fromAtom . nameAtom

instance Binary Name where
    put = put . nameAtom
    get = fmap fromAtom get

instance FromAtom Name where
    fromAtom atom = let (nt, mod, i) = genNameParts atom
                        name = Name { nameAtom = atom
                                    , nameHash = hash32 atom
                                    , nameType = nt
                                    , nameModule = mod
                                    , nameIdent = i }
                    in name
instance ToAtom Name where
    toAtom = nameAtom

instance Eq Name where
    a == b = nameAtom a == nameAtom b
    a /= b = nameAtom a /= nameAtom b

-- Comparing ByteString's is relatively slow. Try to avoid it.
instance Ord Name where
   a `compare` b = case nameHash a `compare` nameHash b of
                     EQ -> if nameAtom a == nameAtom b
                           then EQ
                           else nameString a `compare` nameString b
                     other -> other

isTypeNamespace TypeConstructor = True
isTypeNamespace ClassName = True
isTypeNamespace TypeVal = True
isTypeNamespace _ = False

isValNamespace DataConstructor = True
isValNamespace Val = True
isValNamespace _ = False

isConstructorLike xs@(x:_) =  isUpper x || x `elem` ":("  || xs == "->"
isConstructorLike [] = error "isConstructorLike: empty"

fromTypishHsName, fromValishHsName :: HsName -> Name
fromTypishHsName name
    | isUpper x || x `elem` ":(" = toName TypeConstructor name
    | otherwise = toName TypeVal name
    where (x:_) = (hsIdentString . hsNameIdent  $ name)
fromValishHsName name
    | isUpper x || x `elem` ":(" = toName DataConstructor name
    | otherwise = toName Val name
    where (x:_) = (hsIdentString . hsNameIdent  $ name)

createName _ "" i = error $ "createName: empty module "  ++ i
createName _ m "" = error $ "createName: empty ident "   ++ m
createName t m i = fromAtom $  toAtom $ (chr $  ord '1' + fromEnum t):m ++ ";" ++ i
createUName :: NameType -> String -> Name
createUName _ "" = error $ "createUName: empty ident"
createUName t i =  fromAtom $ toAtom $ (chr $ fromEnum t + ord '1'):";" ++ i

class ToName a where
    toName :: NameType -> a -> Name
    fromName :: Name -> (NameType, a)

instance ToName HsName where
    toName nt n = m where
        i = hsIdentString $ hsNameIdent n
        m | Qual (Module m) _ <- n = createName nt m i
          | otherwise = createUName nt i
    fromName n = (nameType n, nameName n)

instance ToName (String,String) where
    toName nt (m,i) = createName nt m i
    fromName n = case nameParts n of
            (nt,Just m,i) -> (nt,(m,i))
            (nt,Nothing,i) -> (nt,("",i))

instance ToName (Maybe String,String) where
    toName nt (Just m,i) = createName nt m i
    toName nt (Nothing,i) = createUName nt i
    fromName n = case nameParts n of
        (nt,a,b) -> (nt,(a,b))

instance ToName (Maybe Module,String) where
    toName nt (Just (Module m),i) = createName nt m i
    toName nt (Nothing,i) = createUName nt i
    fromName n = case nameParts n of
        (nt,a,b) -> (nt,(fmap Module a,b))

instance ToName String where
    toName nt i = createUName nt i
    fromName n = (nameType n, mi ) where
        mi = case snd $ fromName n of
            (Just m,i) -> m ++ "." ++ i
            (Nothing,i) -> i


getModule :: Monad m => Name -> m Module
getModule n = case nameParts n of
    (_,Just m,_)  -> return (Module m)
    _ -> fail "Name is unqualified."

toUnqualified :: Name -> Name
toUnqualified n = case nameParts n of
    (_,Nothing,_) -> n
    (t,Just _,i) -> toName t i

qualifyName :: Module -> Name -> Name
qualifyName m n = case nameParts n of
    (t,Nothing,n) -> toName t (Just m, n)
    _ -> n

setModule :: Module -> Name -> Name
setModule m n = qualifyName m  $ toUnqualified n


parseName :: NameType -> String -> Name
parseName t name = toName t (intercalate "." ms, intercalate "." (ns ++ [last sn])) where
    sn = (split (== '.') name)
    (ms,ns) = span validMod (init sn)
    validMod (c:cs) = isUpper c && all (\c -> isAlphaNum c || c `elem` "_'") cs
    validMod _ = False


genNameType :: Atom -> NameType
genNameType a = toEnum $ fromIntegral ( a `unsafeByteIndex` 0) - ord '1'

nameName :: Name -> HsName
nameName (Name _ _ _ (Just mod) i)
    = Qual (Module mod) (HsIdent i)
nameName (Name _ _ _ Nothing i)
    = UnQual $ HsIdent i

nameParts :: Name -> (NameType, Maybe String, String)
nameParts name = (nameType name, nameModule name, nameIdent name)

genNameParts :: Atom -> (NameType,Maybe String,String)
genNameParts n = f $ tail (fromAtom n) where
    f (';':xs) = (genNameType n,Nothing,xs)
    f xs = (genNameType n,Just a,b) where
        (a,_:b) = span (/= ';') xs

instance Show Name where
    show a = show $ nameName a

instance DocLike d => PPrint d Name  where
    pprint n = text (show n)

mapName :: (String -> String,String -> String) -> Name -> Name
mapName (f,g) n = case nameParts n of
    (nt,Nothing,i) -> toName nt (g i)
    (nt,Just m,i) -> toName nt (Just (f m :: String),g i)

mainModule = Module "Main@"

ffiExportName :: FfiExport -> Name
ffiExportName (FfiExport cn _ cc) = toName Val ("FE@", show cc ++ "." ++ cn)