{-# LANGUAGE CPP, PatternSynonyms, ViewPatterns, OverloadedStrings #-}
module HsDev.Symbols.Name (
Name, qualName, unqualName, nameModule, nameIdent, pattern Name, fromName_, toName_, toModuleName_, fromModuleName_, fromName, toName,
name_, moduleName_
) where
import Control.Arrow
import Control.Lens
import Data.Char (isAlpha, isAlphaNum)
import Data.Text (Text)
import Data.String (fromString)
import qualified Data.Text as T
import Language.Haskell.Exts (QName(..), ModuleName(..), Boxed(..), SpecialCon(..))
import qualified Language.Haskell.Exts as Exts (Name(..))
type Name = QName ()
qualName :: String -> String -> Name
qualName m = Qual () (ModuleName () m) . toName_ . fromString
unqualName :: String -> Name
unqualName = UnQual () . toName_ . fromString
nameModule :: Name -> Maybe Text
nameModule (Qual _ (ModuleName _ m) _) = Just $ fromString m
nameModule _ = Nothing
nameIdent :: Name -> Text
nameIdent (Qual _ _ n) = fromName_ n
nameIdent (UnQual _ n) = fromName_ n
nameIdent s = fromName s
pattern Name :: Maybe Text -> Text -> Name
pattern Name m n <- ((nameModule &&& nameIdent) -> (m, n)) where
Name Nothing n = UnQual () (Exts.Ident () (T.unpack n))
Name (Just m) n = Qual () (ModuleName () (T.unpack m)) (Exts.Ident () (T.unpack n))
fromName_ :: Exts.Name () -> Text
fromName_ (Exts.Ident _ s') = fromString s'
fromName_ (Exts.Symbol _ s') = fromString s'
toName_ :: Text -> Exts.Name ()
toName_ txt
| T.null txt = Exts.Ident () ""
| isAlpha (T.head txt) && (T.all validChar $ T.tail txt) = Exts.Ident () . T.unpack $ txt
| otherwise = Exts.Symbol () . T.unpack $ txt
where
validChar ch = isAlphaNum ch || ch == '_'
toModuleName_ :: Text -> ModuleName ()
toModuleName_ = ModuleName () . T.unpack
fromModuleName_ :: ModuleName () -> Text
fromModuleName_ (ModuleName () m) = T.pack m
toName :: Text -> Name
toName "()" = Special () (UnitCon ())
toName "[]" = Special () (ListCon ())
toName "->" = Special () (FunCon ())
toName "(:)" = Special () (Cons ())
toName "(# #)" = Special () (UnboxedSingleCon ())
toName tup
| T.all (== ',') noBraces = Special () (TupleCon () Boxed (succ $ T.length noBraces))
where
noBraces = T.dropAround (`elem` ['(', ')']) tup
toName n = case T.split (== '.') n of
[n'] -> UnQual () (Exts.Ident () $ T.unpack n')
ns -> Qual () (ModuleName () (T.unpack $ T.intercalate "." $ init ns)) (toName_ $ last ns)
fromName :: Name -> Text
fromName (Qual _ (ModuleName _ m) n) = T.concat [fromString m, ".", fromName_ n]
fromName (UnQual _ n) = fromName_ n
fromName (Special _ c) = case c of
UnitCon _ -> "()"
ListCon _ -> "[]"
FunCon _ -> "->"
TupleCon _ _ i -> fromString $ "(" ++ replicate (pred i) ',' ++ ")"
Cons _ -> "(:)"
UnboxedSingleCon _ -> "(# #)"
#if MIN_VERSION_haskell_src_exts(1,20,0)
ExprHole _ -> "_"
#endif
name_ :: Iso' (Exts.Name ()) Text
name_ = iso fromName_ toName_
moduleName_ :: Iso' (ModuleName ()) Text
moduleName_ = iso fromModuleName_ toModuleName_