flp-0.1.0.0: src/Language/Rust/Data/Ident.hs
{-|
Module : Language.Rust.Data.Ident
Description : Identifiers
Copyright : (c) Alec Theriault, 2017-2018
License : BSD-style
Maintainer : alec.theriault@gmail.com
Stability : experimental
Portability : portable
Data structure behind identifiers.
-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
module Language.Rust.Data.Ident (Ident(..), mkIdent, Name, IdentName(..) ) where
import GHC.Generics ( Generic )
import Control.DeepSeq ( NFData )
import Data.Data ( Data )
import Data.Typeable ( Typeable )
import Data.List ( foldl' )
import Data.Char ( ord )
import Data.String ( IsString(..) )
--import Data.Semigroup as Sem
-- | An identifier
data Ident
= Ident { name :: IdentName -- ^ payload of the identifier
, raw :: Bool -- ^ whether the identifier is raw
, hash :: {-# UNPACK #-} !Int -- ^ hash for quick comparision
} deriving (Data, Typeable, Generic, NFData)
-- | Shows the identifier as a string (for use with @-XOverloadedStrings@)
instance Show Ident where
show = show . name
instance IsString Ident where
fromString = mkIdent
-- | Uses 'hash' to short-circuit
instance Eq Ident where
i1 == i2 = hash i1 == hash i2 && name i1 == name i2 && raw i1 == raw i2
i1 /= i2 = hash i1 /= hash i2 || name i1 /= name i2 || raw i1 /= raw i2
-- | Uses 'hash' to short-circuit
instance Ord Ident where
compare i1 i2 = case compare i1 i2 of
EQ -> compare (raw i1, name i1) (raw i2, name i2)
rt -> rt
-- | "Forgets" about whether either argument was raw
instance Monoid Ident where
mappend = (<>)
mempty = mkIdent ""
-- | "Forgets" about whether either argument was raw
-- <<<<<<< HEAD
instance Semigroup Ident where
Ident (Name n1) _ _ <> Ident (Name n2) _ _ = mkIdent (n1 <> n2)
Ident (HaskellName n1) _ _ <> Ident (HaskellName n2) _ _ = mkIdent (n1 <> n2)
Ident (Name n1) _ _ <> Ident (HaskellName n2) _ _ = mkIdent (n1 <> n2)
Ident (HaskellName n1) _ _ <> Ident (Name n2) _ _ = mkIdent (n1 <> n2)
-- =======
-- instance Sem.Semigroup Ident where
-- Ident n1 _ _ <> Ident n2 _ _ = mkIdent (n1 <> n2)
-- >>>>>>> upstream/master
-- | Smart constructor for making an 'Ident'.
mkIdent :: String -> Ident
mkIdent ('$':'{':'i':'|':ss) = Ident (HaskellName $ init $ init ss) False (hashString $ init $ init ss)
mkIdent s = Ident (Name s) False (hashString s)
-- | Hash a string into an 'Int'
hashString :: String -> Int
hashString = foldl' f golden
where f m c = fromIntegral (ord c) * magic + m
magic = 0xdeadbeef
golden = 1013904242
-- | The payload of an identifier
type Name = String
data IdentName =
Name Name
| HaskellName String
deriving (Eq, Ord, Data, Typeable, Generic, NFData)
instance Show IdentName where
show (Name n) = show n
show (HaskellName n) = "${i|" ++ n ++ "|}"