-- Copyright 2019 Google LLC -- -- Use of this source code is governed by a BSD-style -- license that can be found in the LICENSE file or at -- https://developers.google.com/open-source/licenses/bsd {-# LANGUAGE CPP #-} module GHC.SourceGen.Name.Internal where import Data.Char (isAlphaNum, isUpper) import Data.List (intercalate) import Data.String (IsString(..)) #if MIN_VERSION_ghc(9,0,0) import GHC.Data.FastString (FastString, fsLit) import GHC.Unit.Module (mkModuleNameFS, ModuleName, moduleNameString) import GHC.Types.Name.Occurrence import GHC.Types.Name.Reader import GHC.Types.SrcLoc (Located) #else import FastString (FastString, fsLit) import Module (mkModuleNameFS, ModuleName, moduleNameString) import OccName import RdrName import SrcLoc (Located) #endif import GHC.SourceGen.Syntax.Internal (builtLoc) -- | A string identifier referring to a name. -- -- 'OccNameStr' keeps track of whether it is a "constructor" or "variable" -- (e.g.: @\"Foo\"@ vs @\"foo\"@, respectively). -- -- 'OccNameStr' is simililar in purpose to GHC's 'OccName'. However, unlike -- 'OccName', 'OccNameStr' does not differentiate between the namespace -- of types and of values. -- Functions in this package that take an 'OccNameStr' as input -- will internally convert it to the proper namespace. (This approach -- makes it easier to implement an 'IsString' instance without the context -- where a name would be used.) data OccNameStr = OccNameStr !RawNameSpace !FastString deriving (Show, Eq, Ord) data RawNameSpace = Constructor | Value deriving (Show, Eq, Ord) -- TODO: symbols rawNameSpace :: String -> RawNameSpace rawNameSpace (c:_) | isUpper c = Constructor rawNameSpace _ = Value instance IsString OccNameStr where fromString s = OccNameStr (rawNameSpace s) (fsLit s) valueOccName, typeOccName :: OccNameStr -> OccName valueOccName (OccNameStr Constructor s) = mkDataOccFS s valueOccName (OccNameStr Value s) = mkVarOccFS s typeOccName (OccNameStr Constructor s) = mkTcOccFS s typeOccName (OccNameStr Value s) = mkTyVarOccFS s -- | A newtype wrapper around 'ModuleName' which is an instance of 'IsString'. newtype ModuleNameStr = ModuleNameStr { unModuleNameStr :: ModuleName } deriving (Eq, Ord) instance Show ModuleNameStr where show = show . moduleNameString . unModuleNameStr instance IsString ModuleNameStr where fromString = ModuleNameStr . mkModuleNameFS . fsLit -- | A string identifier which may be qualified to a particular module. -- -- 'RdrNameStr' wraps an 'OccNameStr' and thus keeps track of whether it is a -- "constructor" or "variable" (e.g.: @\"Foo.Bar\"@ vs @\"Foo.bar\"@, -- respectively). -- -- 'RdrNameStr' is simililar in purpose to GHC's 'RdrName'. However, unlike -- 'RdrName', 'RdrNameStr' does not differentiate between the namespace of types -- and of values. -- Functions in this package that take a 'RdrNameStr' as input -- will internally convert it to the proper namespace. (This approach -- makes it easier to implement an 'IsString' instance without the context -- where a name would be used.) -- -- For example: -- -- > fromString "A.B.c" == QualStr (fromString "A.B") (fromString "c") -- > fromString "c" == UnqualStr (fromString "c") data RdrNameStr = UnqualStr OccNameStr | QualStr ModuleNameStr OccNameStr deriving (Show, Eq, Ord) -- GHC always wraps RdrName in a Located. (Usually: 'Located (IdP pass)') -- So for convenience, these functions return a Located-wrapped value. valueRdrName, typeRdrName :: RdrNameStr -> Located RdrName valueRdrName (UnqualStr r) = builtLoc $ Unqual $ valueOccName r valueRdrName (QualStr (ModuleNameStr m) r) = builtLoc $ Qual m $ valueOccName r typeRdrName (UnqualStr r) = builtLoc $ Unqual $ typeOccName r typeRdrName (QualStr (ModuleNameStr m) r) = builtLoc $ Qual m $ typeOccName r -- TODO: operators instance IsString RdrNameStr where -- Split "Foo.Bar.baz" into ("Foo.Bar", "baz") fromString s = case collectModuleName s of (m, n) | null m -> UnqualStr (fromString n) | otherwise -> QualStr (fromString $ intercalate "." m) (fromString n) collectModuleName :: String -> ([String],String) collectModuleName s = case span isVarChar s of ("", n) -> ([], n) -- Symbol (n, "") -> ([], n) -- Identifier (m, '.' : s') -> case collectModuleName s' of (m', s'') -> (m : m', s'') _ -> error $ "Unable to parse RdrNameStr: " ++ show s where isVarChar '\'' = True isVarChar '_' = True isVarChar c = isAlphaNum c -- | A RdrName suitable for an import or export list. -- E.g.: `import F(a, B)` -- The 'a' should be a value, but the 'B' should be a type/class. -- (Currently, GHC doesn't distinguish the class and type namespaces.) exportRdrName :: RdrNameStr -> Located RdrName exportRdrName (UnqualStr r) = builtLoc $ Unqual $ exportOccName r exportRdrName (QualStr (ModuleNameStr m) r) = builtLoc $ Qual m $ exportOccName r exportOccName :: OccNameStr -> OccName exportOccName (OccNameStr Value s) = mkVarOccFS s exportOccName (OccNameStr Constructor s) = mkTcOccFS s