packages feed

curry-frontend-0.1: src/Ident.lhs

> {-# LANGUAGE DeriveDataTypeable #-}

% $Id: Ident.lhs,v 1.21 2004/10/29 13:08:09 wlux Exp $
%
% Copyright (c) 1999-2004, Wolfgang Lux
% See LICENSE for the full license.
%
\nwfilename{Ident.lhs}
\section{Identifiers}
This module provides the implementation of identifiers and some
utility functions for identifiers, which are used at various places in
the compiler.

Identifiers comprise the name of the denoted entity and an \emph{id},
which can be used for renaming identifiers, e.g., in order to resolve
name conflicts between identifiers from different scopes. An
identifier with an \emph{id} $0$ is considered as not being renamed
and, hence, its \emph{id} will not be shown.

\ToDo{Probably we should use \texttt{Integer} for the \emph{id}s.}

Qualified identifiers may optionally be prefixed by a module
name. \textbf{The order of the cases \texttt{UnqualIdent} and
\texttt{QualIdent} is important. Some parts of the compiler rely on
the fact that all qualified identifiers are greater than any
unqualified identifier.}
\begin{verbatim}

> module Ident(Ident,QualIdent,ModuleIdent,SrcRefOf(..),
>              mkIdent,name,qualName,uniqueId,renameIdent,unRenameIdent,
>              mkMIdent,moduleName,moduleQualifiers,isInfixOp,isQInfixOp,
>              qualify,qualifyWith,qualQualify,isQualified,
>              unqualify,qualUnqualify,localIdent,splitQualIdent,
>              emptyMIdent,mainMIdent,preludeMIdent,
>              anonId,unitId,boolId,charId,intId,floatId,listId,ioId,
>              successId,trueId,falseId,nilId,consId,mainId,
>              tupleId,isTupleId,tupleArity,
>              minusId,fminusId,updIdentName,
>              qUnitId,qBoolId,qCharId,qIntId,qFloatId,qListId,qIOId,
>              qSuccessId,qTrueId,qFalseId,qNilId,qConsId,
>              qTupleId,isQTupleId,qTupleArity,
>              fpSelectorId,isFpSelectorId,isQualFpSelectorId,
>              recSelectorId,qualRecSelectorId,
>              recUpdateId, qualRecUpdateId, recordExtId, labelExtId,
>              isRecordExtId, isLabelExtId, fromRecordExtId, fromLabelExtId,
>              renameLabel, isLabel, fpSelExt, recSelExt, recUpdExt,
>              recordExt, labelExt, mkLabelIdent,hasPositionIdent,
>              showsIdent,showsQualIdent,showsModuleIdent,
>              addPositionIdent, removePositionIdent, positionOfIdent,
>              addPositionModuleIdent, removePositionModuleIdent,addRef,addRefId,
>              positionOfModuleIdent,positionOfQualIdent,updQualIdent ) where

> import Data.Char
> import Data.List
> import Data.Maybe
> import Data.Generics

> import Position


> data Ident = Ident String Int 
>            | IdentPosition Position String Int deriving (Read,Data,Typeable)
> data QualIdent = UnqualIdent Ident | QualIdent ModuleIdent Ident
>                  deriving (Eq,Ord,Read,Data,Typeable)
> data ModuleIdent = ModuleIdent [String] 
>                   |ModuleIdentPosition Position [String] deriving (Data,Typeable)

> instance Eq Ident where
>    ident1 == ident2 = name ident1 == name     ident2 && 
>                   uniqueId ident1 == uniqueId ident2

> instance Ord ModuleIdent where
>    mident1 `compare` mident2 =
>        moduleQualifiers mident1 `compare` moduleQualifiers mident2

> instance Eq ModuleIdent where
>    mident1 == mident2 = moduleQualifiers mident1 == moduleQualifiers mident2 

> instance Read ModuleIdent where
>   readsPrec p s = [ (mkMIdent [m],s') | (m,s') <- readsPrec p s ]

> instance Ord Ident where
>    ident1 `compare` ident2 =
>        (name ident1,uniqueId ident1) `compare` (name ident2,uniqueId ident2)

> instance Show Ident where
>   showsPrec _ (Ident x n)
>     | n == 0 = showString x
>     | otherwise = showString x . showChar '.' . shows n
>   showsPrec _ (IdentPosition _ x n)
>     | n == 0 = showString x
>     | otherwise = showString x . showChar '.' . shows n
> instance Show QualIdent where
>   showsPrec _ (UnqualIdent x) = shows x
>   showsPrec _ (QualIdent m x) = shows m . showChar '.' . shows x
> instance Show ModuleIdent where
>   showsPrec _ m = showString (moduleName m)

> hasPositionIdent :: Ident -> Bool
> hasPositionIdent (Ident _ _ ) = False
> hasPositionIdent (IdentPosition _ _ _) = True

> addPositionIdent :: Position -> Ident -> Ident
> addPositionIdent pos (Ident x n) = IdentPosition pos x n
> addPositionIdent AST{ast=sr} (IdentPosition pos x n) = 
>   IdentPosition pos{ast=sr} x n
> addPositionIdent pos (IdentPosition _ x n) = 
>   IdentPosition pos x n

> removePositionIdent :: Ident -> Ident
> removePositionIdent (Ident x n) = (Ident x n)
> removePositionIdent (IdentPosition _ x n) = (Ident x n)

> positionOfIdent :: Ident -> Position
> positionOfIdent (Ident _ _) = noPos
> positionOfIdent (IdentPosition pos _ _) = pos

> addPositionModuleIdent :: Position -> ModuleIdent -> ModuleIdent
> addPositionModuleIdent pos (ModuleIdent x) = ModuleIdentPosition pos x 
> addPositionModuleIdent pos (ModuleIdentPosition _ x) = ModuleIdentPosition pos x 

> removePositionModuleIdent :: ModuleIdent -> ModuleIdent
> removePositionModuleIdent (ModuleIdent x) = (ModuleIdent x)
> removePositionModuleIdent (ModuleIdentPosition _ x) = (ModuleIdent x)

> positionOfModuleIdent :: ModuleIdent -> Position
> positionOfModuleIdent (ModuleIdent _) = noPos
> positionOfModuleIdent (ModuleIdentPosition pos _) = pos

> positionOfQualIdent :: QualIdent -> Position
> positionOfQualIdent = positionOfIdent . snd . splitQualIdent

> mkIdent :: String -> Ident
> mkIdent x = Ident x 0

> name :: Ident -> String
> name (Ident x _) = x
> name (IdentPosition _ x _) = x

> qualName :: QualIdent -> String
> qualName (UnqualIdent x) = name x
> qualName (QualIdent m x) = moduleName m ++ "." ++ name x

> uniqueId :: Ident -> Int
> uniqueId (Ident _ n) = n
> uniqueId (IdentPosition _ _ n) = n

> renameIdent :: Ident -> Int -> Ident
> renameIdent (Ident x _) n = Ident x n
> renameIdent (IdentPosition p x _) n = IdentPosition p x n

> unRenameIdent :: Ident -> Ident
> unRenameIdent (Ident x _) = Ident x 0
> unRenameIdent (IdentPosition p x _) = IdentPosition p x 0

> mkMIdent :: [String] -> ModuleIdent
> mkMIdent = ModuleIdent

> moduleName :: ModuleIdent -> String
> moduleName (ModuleIdent xs) = concat (intersperse "." xs)
> moduleName (ModuleIdentPosition _ xs) = concat (intersperse "." xs)

> moduleQualifiers :: ModuleIdent -> [String]
> moduleQualifiers (ModuleIdent xs) = xs
> moduleQualifiers (ModuleIdentPosition _ xs) = xs

> isInfixOp :: Ident -> Bool
> isInfixOp (Ident ('<':c:cs) _)=
>   last (c:cs) /= '>' || not (isAlphaNum c) && c `notElem` "_(["
> isInfixOp (Ident (c:_) _) = not (isAlphaNum c) && c `notElem` "_(["
> isInfixOp (Ident _ _) = False -- error "Zero-length identifier"
> isInfixOp x@(IdentPosition _ _ _) = isInfixOp $ removePositionIdent x

> isQInfixOp :: QualIdent -> Bool
> isQInfixOp (UnqualIdent x) = isInfixOp x
> isQInfixOp (QualIdent _ x) = isInfixOp x

\end{verbatim}
The functions \texttt{qualify} and \texttt{qualifyWith} convert an
unqualified identifier into a qualified identifier (without and with a
given module prefix, respectively).
\begin{verbatim}

> qualify :: Ident -> QualIdent
> qualify = UnqualIdent

> qualifyWith :: ModuleIdent -> Ident -> QualIdent
> qualifyWith = QualIdent

> qualQualify :: ModuleIdent -> QualIdent -> QualIdent
> qualQualify m (UnqualIdent x) = QualIdent m x
> qualQualify _ x = x

> isQualified :: QualIdent -> Bool
> isQualified (UnqualIdent _) = False
> isQualified (QualIdent _ _) = True

> unqualify :: QualIdent -> Ident
> unqualify (UnqualIdent x) = x
> unqualify (QualIdent _ x) = x

> qualUnqualify :: ModuleIdent -> QualIdent -> QualIdent
> qualUnqualify m (UnqualIdent x) = UnqualIdent x
> qualUnqualify m (QualIdent m' x)
>   | m == m' = UnqualIdent x
>   | otherwise = QualIdent m' x

> localIdent :: ModuleIdent -> QualIdent -> Maybe Ident
> localIdent _ (UnqualIdent x) = Just x
> localIdent m (QualIdent m' x)
>   | m == m' = Just x
>   | otherwise = Nothing

> splitQualIdent :: QualIdent -> (Maybe ModuleIdent,Ident)
> splitQualIdent (UnqualIdent x) = (Nothing,x)
> splitQualIdent (QualIdent m x) = (Just m,x)

> updQualIdent :: (ModuleIdent -> ModuleIdent) -> (Ident -> Ident) -> QualIdent -> QualIdent
> updQualIdent _ g (UnqualIdent x) = UnqualIdent (g x)
> updQualIdent f g (QualIdent m x) = QualIdent (f m) (g x)

> addRef :: SrcRef -> QualIdent -> QualIdent
> addRef r = updQualIdent id (addRefId r)

> addRefId :: SrcRef -> Ident -> Ident
> addRefId r = addPositionIdent (AST r)

\end{verbatim}
A few identifiers a predefined here.
\begin{verbatim}

> emptyMIdent, mainMIdent, preludeMIdent :: ModuleIdent
> emptyMIdent   = ModuleIdent []
> mainMIdent    = ModuleIdent ["main"]
> preludeMIdent = ModuleIdent ["Prelude"]

> anonId :: Ident
> anonId = Ident "_" 0

> unitPId :: Position -> Ident
> unitPId p = IdentPosition p "()" 0

> unitId, boolId, charId, intId, floatId, listId, ioId, successId :: Ident
> unitId    = Ident "()" 0
> boolId    = Ident "Bool" 0
> charId    = Ident "Char" 0
> intId     = Ident "Int" 0
> floatId   = Ident "Float" 0
> listId    = Ident "[]" 0
> ioId      = Ident "IO" 0
> successId = Ident "Success" 0

> trueId, falseId, nilId, consId :: Ident
> trueId  = Ident "True" 0
> falseId = Ident "False" 0
> nilId   = Ident "[]" 0
> consId  = Ident ":" 0

> tupleId :: Int -> Ident
> tupleId n
>   | n >= 2 = Ident ("(" ++ replicate (n - 1) ',' ++ ")") 0
>   | otherwise = error "internal error: tupleId"

> isTupleId :: Ident -> Bool
> isTupleId x = n > 1 && x == tupleId n
>   where n = length (name x) - 1

> tupleArity :: Ident -> Int
> tupleArity x
>   | n > 1 && x == tupleId n = n
>   | otherwise = error "internal error: tupleArity"
>   where n = length (name x) - 1

> mainId, minusId, fminusId :: Ident
> mainId = Ident "main" 0
> minusId = Ident "-" 0
> fminusId = Ident "-." 0

> qUnitId, qNilId, qConsId, qListId :: QualIdent
> qUnitId = UnqualIdent unitId
> qListId = UnqualIdent listId
> qNilId  = UnqualIdent nilId
> qConsId = UnqualIdent consId

> qBoolId, qCharId, qIntId, qFloatId, qSuccessId, qIOId :: QualIdent
> qBoolId = QualIdent preludeMIdent boolId
> qCharId = QualIdent preludeMIdent charId
> qIntId = QualIdent preludeMIdent intId
> qFloatId = QualIdent preludeMIdent floatId
> qSuccessId = QualIdent preludeMIdent successId
> qIOId = QualIdent preludeMIdent ioId

> qTrueId, qFalseId :: QualIdent
> qTrueId = QualIdent preludeMIdent trueId
> qFalseId = QualIdent preludeMIdent falseId

> qTupleId :: Int -> QualIdent
> qTupleId = UnqualIdent . tupleId

> isQTupleId :: QualIdent -> Bool
> isQTupleId = isTupleId . unqualify

> qTupleArity :: QualIdent -> Int
> qTupleArity = tupleArity . unqualify

\end{verbatim}
Micellaneous function for generating and testing extended identifiers.
\begin{verbatim}

> fpSelectorId :: Int -> Ident
> fpSelectorId n = Ident (fpSelExt ++ show n) 0

> isFpSelectorId :: Ident -> Bool
> isFpSelectorId f = any (fpSelExt `isPrefixOf`) (tails (name f))

> isQualFpSelectorId :: QualIdent -> Bool
> isQualFpSelectorId = isFpSelectorId . unqualify

> recSelectorId :: QualIdent -> Ident -> Ident
> recSelectorId r l =
>   mkIdent (recSelExt ++ name (unqualify r) ++ "." ++ name l)

> qualRecSelectorId :: ModuleIdent -> QualIdent -> Ident -> QualIdent
> qualRecSelectorId m r l = qualifyWith m' (recSelectorId r l)
>   where m' = (fromMaybe m (fst (splitQualIdent r)))

> recUpdateId :: QualIdent -> Ident -> Ident
> recUpdateId r l = 
>   mkIdent (recUpdExt ++ name (unqualify r) ++ "." ++ name l)

> qualRecUpdateId :: ModuleIdent -> QualIdent -> Ident -> QualIdent
> qualRecUpdateId m r l = qualifyWith m' (recUpdateId r l)
>   where m' = (fromMaybe m (fst (splitQualIdent r)))

> recordExtId :: Ident -> Ident
> recordExtId r = mkIdent (recordExt ++ name r)

> labelExtId :: Ident -> Ident
> labelExtId l = mkIdent (labelExt ++ name l)

> fromRecordExtId :: Ident -> Ident
> fromRecordExtId r 
>   | p == recordExt = mkIdent r'
>   | otherwise = r
>  where (p,r') = splitAt (length recordExt) (name r)

> fromLabelExtId :: Ident -> Ident
> fromLabelExtId l 
>   | p == labelExt = mkIdent l'
>   | otherwise = l
>  where (p,l') = splitAt (length labelExt) (name l)

> isRecordExtId :: Ident -> Bool
> isRecordExtId r = recordExt `isPrefixOf` name r

> isLabelExtId :: Ident -> Bool
> isLabelExtId l = labelExt `isPrefixOf` name l

> mkLabelIdent :: String -> Ident
> mkLabelIdent c = renameIdent (mkIdent c) (-1)

> renameLabel :: Ident -> Ident
> renameLabel l = renameIdent l (-1)

> isLabel :: Ident -> Bool
> isLabel l = uniqueId l == (-1)


> fpSelExt = "_#selFP"
> recSelExt = "_#selR@"
> recUpdExt = "_#updR@"
> recordExt = "_#Rec:"
> labelExt = "_#Lab:"

> showsString :: String -> ShowS
> showsString = (++)

> space :: ShowS
> space = showsString " "

> showsIdent :: Ident -> ShowS
> showsIdent x@(IdentPosition _ _ _) = showsIdent $ removePositionIdent x
> showsIdent (Ident name n)
>   = showsString "(Ident " . shows name . space . shows n . showsString ")"

> showsQualIdent :: QualIdent -> ShowS
> showsQualIdent (UnqualIdent ident)
>   = showsString "(UnqualIdent " . showsIdent ident . showsString ")"
> showsQualIdent (QualIdent mident ident)
>   = showsString "(QualIdent "
>   . showsModuleIdent mident . space
>   . showsIdent ident
>   . showsString ")"

> showsModuleIdent :: ModuleIdent -> ShowS
> showsModuleIdent = shows . moduleName

showsModuleIdent x@(ModuleIdentPosition _ _) = 
    showsModuleIdent $ removePositionModuleIdent x
showsModuleIdent (ModuleIdent []) = showsString "(ModuleIdent [])"
showsModuleIdent (ModuleIdent (s:strs))
  = showsString "(ModuleIdent ["
  . foldl (\sys y -> sys . showsString "," . shows y) (shows s) strs
  . showsString "])"

\end{verbatim}

> instance SrcRefOf Ident where srcRefOf = srcRefOf . positionOfIdent
> instance SrcRefOf QualIdent where srcRefOf = srcRefOf . unqualify

> updIdentName :: (String -> String) -> Ident -> Ident
> updIdentName f ident = let p=positionOfIdent ident
>                            i=uniqueId ident
>                            n=name ident in
>   addPositionIdent p $ flip renameIdent i $ mkIdent (f n)