Collecting all external names in a module

Johan Tibell johan.tibell at gmail.com
Fri Sep 10 10:34:32 EDT 2010


Hi,

I have a question regarding the GHC API.

Given a module, I'm trying to collect

 * the Name and SrcSpan of all top-level definitions,
 * the Name and SrcSpan of all (local) uses of these top-level definition
 * the Name and SrcSpan of all uses of imported definitions.

For example, given the file A.hs

    module B where

    data Foo = Bar | Baz String

    main = print $ "Hello, World!" ++ show test

    test = let x = 2 in x

I would like to output:

B.Foo - A.hs:3:5-7
B.Bar - A.hs:3:10-12
B.Baz - A.hs:3:10-12
GHC.Base.String - A.hs:3:13-18
B.main - A.hs:5:1-4
System.IO.print - A.hs:5:8-11
GHC.Base.++ - A.hs:5:18-19
etc.

(The line/column numbers are made up.)

 * I do not want to output e.g. 'x' as it's not a top-level identifier (the
code I've included below gets this wrong).
 * I want to output whether the SrcSpan corresponds to a use site or
definition site of the Name. For example: 'Foo' is a definition site while
'print' is a use site.

I started writing a manual traversal of the RenamedSource AST (as I want
qualified names) but I thought I check if I'm going about this right before
I spend all the time required to write the traversal for the whole AST.

Here's the code I have so far, am I on the right track?

----------

-- | Collects all qualified names that are referred to in a module,
-- that are either defineds at the top-level in that module or that
-- are imported from some other module.
module Main where

import Bag
import DynFlags ( defaultDynFlags )
import GHC
import GHC.Paths ( libdir )
import Outputable
import System.Environment

-- | Is the 'Name' defined here?
data Origin = Local | External
type Use = (Name, Origin, SrcSpan)

local :: Name -> Use
local name = (name, Local, nameSrcSpan name)

external :: Name -> SrcSpan -> Use
external name loc = (name, External, loc)

showName :: (Name, Origin, SrcSpan) -> String
showName (name, org, loc) = showSDoc (ppr name) ++ "," ++
                    showSDoc (ppr loc) ++ "," ++
                    showOrg org
    where showOrg Local = "1"
          showOrg External = "0"

main :: IO ()
main = do
    [targetFile] <- getArgs
    res <- defaultErrorHandler defaultDynFlags $ runGhc (Just libdir) $ do
        dflags <- getSessionDynFlags
        _ <- setSessionDynFlags dflags
        target <- guessTarget targetFile Nothing
        setTargets [target]
        _ <- load LoadAllTargets
        modSum <- getModSummary $ mkModuleName "B"
        p <- parseModule modSum
        t <- typecheckModule p
        let Just (r, _, _, _) = tm_renamed_source t
        return r
    putStrLn $ showSDoc $ ppr res
    putStrLn ""
    putStr $ unlines $ map showName (collectHsGroup res)

------------------------------------------------------------------------
-- AST traversal

-- | Collect all external qualified names in the module.
collectHsGroup :: HsGroup Name -> [Use]
collectHsGroup = collectHsValBindsLR . hs_valds

collectHsValBindsLR :: HsValBindsLR Name Name -> [Use]
collectHsValBindsLR (ValBindsOut xs _) =
    concatMap collectHsBindNames . map unLoc . concatMap bagToList
    . map snd $ xs
collectHsValBindsLR (ValBindsIn binds _) =
    concatMap (collectHsBindNames . unLoc) (bagToList binds)

collectHsBindNames :: HsBindLR Name Name -> [Use]
collectHsBindNames fb@(FunBind { fun_id = L _ f }) =
    [local f] ++ collectMatchGroupNames (fun_matches fb)
collectHsBindNames _ = []

collectMatchGroupNames :: MatchGroup Name -> [Use]
collectMatchGroupNames (MatchGroup matches _) = concat
    [collectGRHSsNames x | Match _ _ x <- map unLoc matches]

collectGRHSsNames :: GRHSs Name -> [Use]
collectGRHSsNames (GRHSs xs _) = concatMap (collectGRHSNames . unLoc) xs

collectGRHSNames :: GRHS Name -> [Use]
collectGRHSNames (GRHS _stmts exprs) =
    collectHsExprNames exprs

-- For less typing
collectHsExprNames :: LHsExpr Name -> [Use]
collectHsExprNames = collect

collect :: LHsExpr Name -> [Use]
collect (L loc expr) = go expr
  where
    go (HsVar name)
        | isExternalName name = [external name loc]
        | otherwise           = []
    go (HsIPVar _)          = []
    go (HsOverLit _)        = []
    go (HsLit _)            = []
    go (HsLam mg)           = collectMatchGroupNames mg
    go (HsApp e1 e2)        = collect e1 ++ collect e2
    go (OpApp e1 e2 _ e3)   = collect e1 ++ collect e2 ++ collect e3
    go (NegApp e1 _)        = collect e1 -- ++ collect e2 -- ???
    go (HsPar e)            = collect e
    go (SectionL e1 e2)     = collect e1 ++ collect e2
    go (SectionR e1 e2)     = collect e1 ++ collect e2
    go (ExplicitTuple xs _) = concat [ collect x | Present x <- xs]
    go (HsCase e mg)        = collect e ++ collectMatchGroupNames mg
    go (HsIf e1 e2 e3)      = collect e1 ++ collect e2 ++ collect e3
    go (HsLet binds e)      = collectHsLocalBindsLR binds ++ collect e
    -- go (HsDo (HsStmtContext Name) [LStmt id] (LHsExpr id) PostTcType) =
    -- go (ExplicitList PostTcType [LHsExpr id]) =
    -- go (ExplicitPArr PostTcType [LHsExpr id]) =
    -- go (RecordCon (Located id) PostTcExpr (HsRecordBinds id)) =
    -- go (RecordUpd (LHsExpr id) (HsRecordBinds id) [DataCon] [PostTcType]
[PostTcType]) =
    -- go (ExprWithTySig (LHsExpr id) (LHsType id)) =
    -- go (ExprWithTySigOut (LHsExpr id) (LHsType Name)) =
    -- go (ArithSeq PostTcExpr (ArithSeqInfo id)) =
    -- go (PArrSeq PostTcExpr (ArithSeqInfo id)) =
    -- go (HsSCC FastString (LHsExpr id)) =
    -- go (HsCoreAnn FastString (LHsExpr id)) =
    -- go (HsBracket (HsBracket id)) =
    -- go (HsBracketOut (HsBracket Name) [PendingSplice]) =
    -- go (HsSpliceE (HsSplice id)) =
    -- go (HsQuasiQuoteE (HsQuasiQuote id)) =
    -- go (HsProc (LPat id) (LHsCmdTop id)) =
    -- go (HsArrApp (LHsExpr id) (LHsExpr id) PostTcType HsArrAppType Bool)
=
    -- go (HsArrForm (LHsExpr id) (Maybe Fixity) [LHsCmdTop id]) =
    -- go (HsTick Int [id] (LHsExpr id)) =
    -- go (HsBinTick Int Int (LHsExpr id)) =
    -- go (HsTickPragma (FastString, (Int, Int), (Int, Int)) (LHsExpr id)) =

    -- go (EWildPat) =
    -- go (EAsPat (Located id) (LHsExpr id)) =
    -- go (EViewPat (LHsExpr id) (LHsExpr id)) =
    -- go (ELazyPat (LHsExpr id)) =
    -- go (HsType (LHsType id)) =
    -- go (HsWrap HsWrapper (HsExpr id)) =
    go _ = []

collectHsLocalBindsLR :: HsLocalBindsLR Name Name -> [Use]
collectHsLocalBindsLR (HsValBinds x) = collectHsValBindsLR x
collectHsLocalBindsLR _ = []
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/glasgow-haskell-users/attachments/20100910/2782b5db/attachment.html


More information about the Glasgow-haskell-users mailing list