{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeFamilies #-}
module Agda.Syntax.Concrete.Name where
import Control.DeepSeq
import Data.ByteString.Char8 (ByteString)
import Data.Function
import qualified Data.Foldable as Fold
import qualified Data.List as List
import Data.Data (Data)
import GHC.Generics (Generic)
import System.FilePath
import Agda.Syntax.Common
import Agda.Syntax.Position
import Agda.Utils.FileName
import Agda.Utils.Lens
import Agda.Utils.Pretty
import Agda.Utils.Size
import Agda.Utils.Suffix
import Agda.Utils.Impossible
data Name
= Name
{ nameRange :: Range
, nameInScope :: NameInScope
, nameNameParts :: [NamePart]
}
| NoName
{ nameRange :: Range
, nameId :: NameId
}
deriving Data
isOpenMixfix :: Name -> Bool
isOpenMixfix n = case n of
Name _ _ (x : xs@(_:_)) -> x == Hole || last xs == Hole
_ -> False
instance Underscore Name where
underscore = NoName noRange __IMPOSSIBLE__
isUnderscore NoName{} = True
isUnderscore (Name {nameNameParts = [Id x]}) = isUnderscore x
isUnderscore _ = False
data NamePart
= Hole
| Id RawName
deriving (Data, Generic)
instance Eq Name where
Name _ _ xs == Name _ _ ys = xs == ys
NoName _ i == NoName _ j = i == j
_ == _ = False
instance Ord Name where
compare (Name _ _ xs) (Name _ _ ys) = compare xs ys
compare (NoName _ i) (NoName _ j) = compare i j
compare (NoName {}) (Name {}) = LT
compare (Name {}) (NoName {}) = GT
instance Eq NamePart where
Hole == Hole = True
Id s1 == Id s2 = s1 == s2
_ == _ = False
instance Ord NamePart where
compare Hole Hole = EQ
compare Hole (Id {}) = LT
compare (Id {}) Hole = GT
compare (Id s1) (Id s2) = compare s1 s2
data QName
= Qual Name QName
| QName Name
deriving (Data, Eq, Ord)
instance Underscore QName where
underscore = QName underscore
isUnderscore (QName x) = isUnderscore x
isUnderscore Qual{} = False
data TopLevelModuleName = TopLevelModuleName
{ moduleNameRange :: Range
, moduleNameParts :: [String]
}
deriving (Show, Data)
instance Eq TopLevelModuleName where (==) = (==) `on` moduleNameParts
instance Ord TopLevelModuleName where compare = compare `on` moduleNameParts
instance Sized TopLevelModuleName where size = size . moduleNameParts
nameToRawName :: Name -> RawName
nameToRawName = prettyShow
nameParts :: Name -> [NamePart]
nameParts (Name _ _ ps) = ps
nameParts (NoName _ _) = [Id "_"]
nameStringParts :: Name -> [RawName]
nameStringParts n = [ s | Id s <- nameParts n ]
stringNameParts :: String -> [NamePart]
stringNameParts "_" = [Id "_"]
stringNameParts s = loop s where
loop "" = []
loop ('_':s) = Hole : loop s
loop s | (x, s') <- break (== '_') s = Id (stringToRawName x) : loop s'
class NumHoles a where
numHoles :: a -> Int
instance NumHoles [NamePart] where
numHoles = length . filter (== Hole)
instance NumHoles Name where
numHoles NoName{} = 0
numHoles (Name { nameNameParts = parts }) = numHoles parts
instance NumHoles QName where
numHoles (QName x) = numHoles x
numHoles (Qual _ x) = numHoles x
isOperator :: Name -> Bool
isOperator (NoName {}) = False
isOperator (Name _ _ ps) = length ps > 1
isHole :: NamePart -> Bool
isHole Hole = True
isHole _ = False
isPrefix, isPostfix, isInfix, isNonfix :: Name -> Bool
isPrefix x = not (isHole (head xs)) && isHole (last xs) where xs = nameParts x
isPostfix x = isHole (head xs) && not (isHole (last xs)) where xs = nameParts x
isInfix x = isHole (head xs) && isHole (last xs) where xs = nameParts x
isNonfix x = not (isHole (head xs)) && not (isHole (last xs)) where xs = nameParts x
data NameInScope = InScope | NotInScope
deriving (Eq, Show, Data)
class LensInScope a where
lensInScope :: Lens' NameInScope a
isInScope :: a -> NameInScope
isInScope x = x ^. lensInScope
mapInScope :: (NameInScope -> NameInScope) -> a -> a
mapInScope = over lensInScope
setInScope :: a -> a
setInScope = mapInScope $ const InScope
setNotInScope :: a -> a
setNotInScope = mapInScope $ const NotInScope
instance LensInScope NameInScope where
lensInScope = id
instance LensInScope Name where
lensInScope f = \case
n@Name{ nameInScope = nis } -> (\nis' -> n { nameInScope = nis' }) <$> f nis
n@NoName{} -> const n <$> f InScope
instance LensInScope QName where
lensInScope f = \case
Qual x xs -> (`Qual` xs) <$> lensInScope f x
QName x -> QName <$> lensInScope f x
nextStr :: String -> String
nextStr s = case suffixView s of
(s0, suf) -> addSuffix s0 (nextSuffix suf)
nextName :: Name -> Name
nextName NoName{} = __IMPOSSIBLE__
nextName x@Name{ nameNameParts = ps } = x { nameInScope = NotInScope, nameNameParts = nextSuf ps }
where
nextSuf [Id s] = [Id $ nextStr s]
nextSuf [Id s, Hole] = [Id $ nextStr s, Hole]
nextSuf (p : ps) = p : nextSuf ps
nextSuf [] = __IMPOSSIBLE__
firstNonTakenName :: (Name -> Bool) -> Name -> Name
firstNonTakenName taken x =
if taken x
then firstNonTakenName taken (nextName x)
else x
nameRoot :: Name -> RawName
nameRoot NoName{} = __IMPOSSIBLE__
nameRoot x@Name{ nameNameParts = ps } =
nameToRawName $ x{ nameNameParts = root ps }
where
root [Id s] = [Id $ strRoot s]
root [Id s, Hole] = [Id $ strRoot s , Hole]
root (p : ps) = p : root ps
root [] = __IMPOSSIBLE__
strRoot = fst . suffixView
sameRoot :: Name -> Name -> Bool
sameRoot = (==) `on` nameRoot
qualify :: QName -> Name -> QName
qualify (QName m) x = Qual m (QName x)
qualify (Qual m m') x = Qual m $ qualify m' x
unqualify :: QName -> Name
unqualify q = unqualify' q `withRangeOf` q
where
unqualify' (QName x) = x
unqualify' (Qual _ x) = unqualify' x
qnameParts :: QName -> [Name]
qnameParts (Qual x q) = x : qnameParts q
qnameParts (QName x) = [x]
isQualified :: QName -> Bool
isQualified Qual{} = True
isQualified QName{} = False
isUnqualified :: QName -> Maybe Name
isUnqualified Qual{} = Nothing
isUnqualified (QName n) = Just n
toTopLevelModuleName :: QName -> TopLevelModuleName
toTopLevelModuleName q = TopLevelModuleName (getRange q) $ map prettyShow $ qnameParts q
moduleNameToFileName :: TopLevelModuleName -> String -> FilePath
moduleNameToFileName (TopLevelModuleName _ []) ext = __IMPOSSIBLE__
moduleNameToFileName (TopLevelModuleName _ ms) ext =
joinPath (init ms) </> last ms <.> ext
projectRoot :: AbsolutePath -> TopLevelModuleName -> AbsolutePath
projectRoot file (TopLevelModuleName _ m) =
mkAbsolute $
foldr (.) id (replicate (length m - 1) takeDirectory) $
takeDirectory $
filePath file
noName_ :: Name
noName_ = noName noRange
noName :: Range -> Name
noName r = NoName r (NameId 0 0)
class IsNoName a where
isNoName :: a -> Bool
default isNoName :: (Foldable t, IsNoName b, t b ~ a) => a -> Bool
isNoName = Fold.all isNoName
instance IsNoName String where
isNoName = isUnderscore
instance IsNoName ByteString where
isNoName = isUnderscore
instance IsNoName Name where
isNoName (NoName _ _) = True
isNoName (Name _ _ [Hole]) = True
isNoName (Name _ _ []) = True
isNoName (Name _ _ [Id x]) = isNoName x
isNoName _ = False
instance IsNoName QName where
isNoName (QName x) = isNoName x
isNoName Qual{} = False
instance IsNoName a => IsNoName (Ranged a) where
instance IsNoName a => IsNoName (WithOrigin a) where
instance Show Name where
show = prettyShow
instance Show NamePart where
show = prettyShow
instance Show QName where
show = prettyShow
instance Pretty Name where
pretty (Name _ _ xs) = hcat $ map pretty xs
pretty (NoName _ _) = "_"
instance Pretty NamePart where
pretty Hole = "_"
pretty (Id s) = text $ rawNameToString s
instance Pretty QName where
pretty (Qual m x)
| isUnderscore m = pretty x
| otherwise = pretty m <> "." <> pretty x
pretty (QName x) = pretty x
instance Pretty TopLevelModuleName where
pretty (TopLevelModuleName _ ms) = text $ List.intercalate "." ms
instance HasRange Name where
getRange (Name r _ ps) = r
getRange (NoName r _) = r
instance HasRange QName where
getRange (QName x) = getRange x
getRange (Qual n x) = fuseRange n x
instance HasRange TopLevelModuleName where
getRange = moduleNameRange
instance SetRange Name where
setRange r (Name _ nis ps) = Name r nis ps
setRange r (NoName _ i) = NoName r i
instance SetRange QName where
setRange r (QName x) = QName (setRange r x)
setRange r (Qual n x) = Qual (setRange r n) (setRange r x)
instance SetRange TopLevelModuleName where
setRange r (TopLevelModuleName _ x) = TopLevelModuleName r x
instance KillRange QName where
killRange (QName x) = QName $ killRange x
killRange (Qual n x) = killRange n `Qual` killRange x
instance KillRange Name where
killRange (Name r nis ps) = Name (killRange r) nis ps
killRange (NoName r i) = NoName (killRange r) i
instance KillRange TopLevelModuleName where
killRange (TopLevelModuleName _ x) = TopLevelModuleName noRange x
instance NFData NameInScope where
rnf InScope = ()
rnf NotInScope = ()
instance NFData Name where
rnf (Name _ nis ns) = rnf nis `seq` rnf ns
rnf (NoName _ n) = rnf n
instance NFData NamePart where
rnf Hole = ()
rnf (Id s) = rnf s
instance NFData QName where
rnf (Qual a b) = rnf a `seq` rnf b
rnf (QName a) = rnf a