hat-2.9.1: tools/Idents.hs
{-# LANGUAGE EmptyDataDecls #-}
module Idents
( Ident(..)
, collateIdents -- :: IO ()
, getAllIdents -- :: IO ([Ident],[Ident],[Ident])
, AllInfo -- type AllInfo = [(String,[(String,Ident)])]
, sortIdents -- :: [Ident] -> AllInfo
, showInfo -- :: String -> AllInfo -> ShowS
) where
import LowLevel (FileNode(..))
import Foreign.Ptr (Ptr)
import Foreign.C.String (CString, peekCString)
import System.IO.Unsafe (unsafePerformIO)
import Foreign.Marshal.Alloc (free)
import Ident (Ident(..),getIdentAt)
import Data.List
import HighlightStyle
---------------------------------------------------------------------
data Item
foreign import ccall "hat-names.h" getItemPtr :: Ptr (Ptr Item) -> Int
-> IO (Ptr Item)
foreign import ccall "hat-names.h" itemIdent :: Ptr Item -> IO FileNode
foreign import ccall "hat-names.h" itemArity :: Ptr Item -> IO Int
foreign import ccall "hat-names.h" itemUses :: Ptr Item -> IO Int
foreign import ccall "hat-names.h" itemPending :: Ptr Item -> IO Int
foreign import ccall "hat-names.h" itemThunks :: Ptr Item -> IO Int
getOneIdent :: Ptr (Ptr Item) -> Int -> IO Ident
getOneIdent a n = do
p <- getItemPtr a n
atom <- itemIdent p
arity <- itemArity p
uses <- itemUses p
pend <- itemPending p
th <- itemThunks p
ident <- getIdentAt atom
free p
return ident
{ i_caf = arity==0
, i_uses = uses
, i_pending = pend
, i_thunks = th
}
foreign import ccall "hat-names.h" collateIdents :: IO ()
foreign import ccall "hat-names.h" getGlobals :: IO (Ptr (Ptr Item))
foreign import ccall "hat-names.h" getLocals :: IO (Ptr (Ptr Item))
foreign import ccall "hat-names.h" getConstrs :: IO (Ptr (Ptr Item))
foreign import ccall "hat-names.h" getGlobalsN :: IO Int
foreign import ccall "hat-names.h" getLocalsN :: IO Int
foreign import ccall "hat-names.h" getConstrsN :: IO Int
getAllIdents :: IO ([Ident],[Ident],[Ident])
getAllIdents = do
g <- getGlobals
gi <- getGlobalsN
l <- getLocals
li <- getLocalsN
c <- getConstrs
ci <- getConstrsN
gs <- getAll g gi
ls <- getAll l li
cs <- getAll c ci
return (gs, ls, cs)
where
getAll :: Ptr (Ptr Item) -> Int -> IO [Ident]
getAll p i = mapM (getOneIdent p) [0..(i-1)]
---------------------------------------------------------------------
{-
-- InfoCmd describes how the data about identifiers should be presented.
-- For the moment, we just implement one style, AllByModule.
data InfoCmd
= AllByModule | AllByAlpha | AllByFrequency
| ModuleByAlpha String | ModuleByFrequency String
| Individual (Maybe String) String
-}
--
-- [(modulename, [(idname,identifier info)])]
type AllInfo = [(String,[(String,Ident)])]
sortIdents :: [Ident] -> AllInfo
sortIdents is = foldr insMod [] is
where
insMod i []
-- exclude identifiers with zero counts
| (i_uses i == 0) && (i_pending i == 0) = []
| otherwise = [(i_modname i, [(i_name i, i)])]
insMod i xs@(o@(x,ys):rest)
| (i_uses i == 0) && (i_pending i == 0) = xs
| i_isTraced i || not (i_caf i) =
let m = i_modname i
n = i_name i in
case compare m x of
LT -> (m,[(n,i)]): xs
-- EQ -> (m, insertBy (\(n,i) (n',i')->compare n n') (n,i) ys): rest
EQ -> (m, merge (n,i) ys): rest
GT -> o : insMod i rest
| otherwise = xs
merge (n,i) [] = [(n,i)]
merge (n,i) ((n',i'):nis) =
case compare n n' of
LT -> (n,i): (n',i'): nis
EQ -> (n, combine i i'): nis
GT -> (n',i'): merge (n,i) nis
where
combine i i' = i { i_uses = i_uses i + i_uses i'
, i_pending = i_pending i + i_pending i'
, i_thunks = i_thunks i + i_thunks i'
}
{-
showInfo :: AllInfo -> ShowS
showInfo xs = foldr (.) id (map showMod xs)
where
showMod (m,ns) = showString (highlight [Foreground Blue] m) . nl .
foldr (.) id (map showIdent ns) . nl
showIdent (n,i) = times 4 space
. (let pend = i_pending i in
if pend>0 then
showString (highlight [Foreground Red] (show pend))
else id)
. showString (highlight [Foreground Blue]
(show (i_uses i)))
. space . showString n
nl = showChar '\n'
space = showChar ' '
times n x = foldr (.) id (replicate n x)
-}
showInfo :: String -> AllInfo -> ShowS
showInfo mod xs =
case mod of
"" -> foldr (.) id (map showMod xs)
_ -> case lookup mod xs of
Just v -> showMod (mod,v)
Nothing -> showString ("module "++mod++" not found.\n")
where
showMod (m,ns) = showString m . trusted ns . nl
. columnate 80 (map showIdent ns) . nl
showIdent (s,i) = (show (i_uses i), s)
nl = showChar '\n'
space = showChar ' '
times n x = foldr (.) id (replicate n x)
trusted ((_,i):_) = if i_isTraced i then id else
showString (highlight [Foreground Blue] " (trusted)")
columnate :: Int -> [(String,String)] -> ShowS
columnate width ns =
let largestN = maximum (map (length.fst) ns)
largestS = maximum (map (length.snd) ns)
numitems = length ns
numcols = width `div` (largestN+largestS+3)
numlines = let x = numitems `mod` numcols
y = numitems `div` numcols in
if x==0 then y else y+1
rjust n s = replicate (n-length s) ' ' ++ s
ljust n s = s ++ replicate (n-length s) ' '
shown (n,s) = highlight [Foreground Blue] (rjust largestN n)
++" "++ ljust largestS s
divided :: Int -> [a] -> [[a]]
divided n [] = []
divided n xs = let (a,b) = splitAt n xs in a: divided n b
-- flipped :: [[a]] -> [[a]]
flipped xss | all null xss = []
flipped xss = map (safe head "") xss : flipped (map (safe tail []) xss)
safe f e xs = if null xs then e else f xs
oneline ns rest = foldr (.) id (map showString (intersperse " " ns))
. showChar '\n' . rest
in
foldr oneline id (flipped (divided numlines (map shown ns)))
---------------------------------------------------------------------