2019-06-10 05:36:18 +03:00
|
|
|
-- Copyright 2019 Google LLC
|
|
|
|
--
|
|
|
|
-- Use of this source code is governed by a BSD-style
|
|
|
|
-- license that can be found in the LICENSE file or at
|
|
|
|
-- https://developers.google.com/open-source/licenses/bsd
|
|
|
|
|
2019-08-11 19:32:44 +03:00
|
|
|
{-# LANGUAGE CPP #-}
|
2019-06-10 05:36:18 +03:00
|
|
|
{-# LANGUAGE GADTs #-}
|
|
|
|
module Main where
|
|
|
|
|
2019-08-11 19:32:44 +03:00
|
|
|
import Data.Data (Data, showConstr, toConstr, gmapQ)
|
2019-06-10 05:36:18 +03:00
|
|
|
import Data.Typeable (cast)
|
|
|
|
import System.Environment (getArgs)
|
|
|
|
import Text.PrettyPrint
|
|
|
|
|
|
|
|
import FastString
|
|
|
|
import Name
|
|
|
|
( Name
|
|
|
|
, isExternalName
|
|
|
|
, isInternalName
|
|
|
|
, isSystemName
|
|
|
|
, isWiredInName
|
|
|
|
, nameOccName
|
|
|
|
, nameUnique
|
|
|
|
)
|
|
|
|
import OccName
|
|
|
|
( OccName
|
|
|
|
, occNameSpace
|
|
|
|
, occNameString
|
|
|
|
, NameSpace
|
|
|
|
, varName
|
|
|
|
, dataName
|
|
|
|
, tvName
|
|
|
|
, tcClsName
|
|
|
|
)
|
|
|
|
|
2019-08-11 19:32:44 +03:00
|
|
|
import qualified DynFlags as GHC
|
|
|
|
import qualified FastString as GHC
|
|
|
|
import qualified GHC as GHC
|
|
|
|
import qualified GhcMonad as GHC
|
|
|
|
import qualified HeaderInfo as GHC
|
|
|
|
import qualified Outputable as GHC
|
|
|
|
import qualified Lexer as GHC
|
|
|
|
import qualified Parser as Parser
|
|
|
|
import qualified SrcLoc as GHC
|
|
|
|
import qualified StringBuffer as GHC
|
|
|
|
import GHC.Paths (libdir)
|
|
|
|
|
2019-06-10 05:36:18 +03:00
|
|
|
main :: IO ()
|
|
|
|
main = do
|
|
|
|
[f] <- getArgs
|
|
|
|
result <- parseModule f
|
2019-08-11 19:32:44 +03:00
|
|
|
print $ gPrint result
|
|
|
|
|
|
|
|
#if MIN_VERSION_ghc(8,4,0)
|
|
|
|
parseModule :: FilePath -> IO (GHC.HsModule GHC.GhcPs)
|
|
|
|
#else
|
|
|
|
parseModule :: FilePath -> IO (GHC.HsModule GHC.RdrName)
|
|
|
|
#endif
|
|
|
|
parseModule f = GHC.runGhc (Just libdir) $ do
|
|
|
|
dflags <- GHC.getDynFlags
|
|
|
|
contents <- GHC.liftIO $ GHC.stringToStringBuffer <$> readFile f
|
|
|
|
let options = GHC.getOptions dflags contents f
|
|
|
|
(dflags', _, _) <- GHC.parseDynamicFilePragma dflags options
|
|
|
|
let state = GHC.mkPState dflags' contents (GHC.mkRealSrcLoc (GHC.fsLit f) 1 1)
|
|
|
|
case GHC.unP Parser.parseModule state of
|
|
|
|
GHC.POk _state m -> return $ GHC.unLoc m
|
|
|
|
GHC.PFailed
|
|
|
|
#if MIN_VERSION_ghc(8,4,0)
|
|
|
|
_message
|
|
|
|
#endif
|
|
|
|
loc docs ->
|
|
|
|
error $ GHC.showPpr dflags loc ++ GHC.showSDoc dflags docs
|
2019-06-10 05:36:18 +03:00
|
|
|
|
|
|
|
gPrint :: Data a => a -> Doc
|
|
|
|
gPrint x
|
|
|
|
| showConstr c == "L", [_,e] <- xs = e
|
|
|
|
| showConstr c == "(:)" = gPrintList x
|
|
|
|
| Just occ <- cast x = text $ showOccName occ
|
|
|
|
| Just name <- cast x = text $ showName name
|
|
|
|
| Just s <- cast x = text $ showFastString s
|
|
|
|
| otherwise =
|
|
|
|
hang (text $ showConstr c) 2 (sep $ map parens xs)
|
|
|
|
where
|
|
|
|
c = toConstr x
|
|
|
|
xs = gmapQ gPrint x
|
|
|
|
|
|
|
|
gPrintList :: Data a => a -> Doc
|
|
|
|
gPrintList = brackets . sep . punctuate comma . elems
|
|
|
|
where
|
|
|
|
elems :: Data b => b -> [Doc]
|
|
|
|
elems xs = case gmapQ SomeData xs of
|
|
|
|
[] -> []
|
|
|
|
[x,y] -> renderCons x y
|
|
|
|
_ -> error $ "gPrintList: unexpected number of fields"
|
|
|
|
renderCons :: SomeData -> SomeData -> [Doc]
|
|
|
|
renderCons (SomeData x) (SomeData y) = gPrint x : elems y
|
|
|
|
|
|
|
|
data SomeData where
|
|
|
|
SomeData :: Data a => a -> SomeData
|
|
|
|
|
|
|
|
showOccName :: OccName -> String
|
|
|
|
showOccName o = "OccName{" ++ showNameSpace (occNameSpace o)
|
|
|
|
++ "," ++ show (occNameString o) ++ "}"
|
|
|
|
|
|
|
|
showFastString :: FastString -> String
|
|
|
|
showFastString = show . unpackFS
|
|
|
|
|
|
|
|
showNameSpace :: NameSpace -> String
|
|
|
|
showNameSpace ns
|
|
|
|
| ns == varName = "VarName"
|
|
|
|
| ns == dataName = "DataName"
|
|
|
|
| ns == tvName = "TvName"
|
|
|
|
| ns == tcClsName = "TcClsName"
|
|
|
|
| otherwise = "Unknown"
|
|
|
|
|
|
|
|
showName :: Name -> String
|
|
|
|
showName n = "Name{" ++ nameSort ++ ":" ++ showOccName (nameOccName n)
|
|
|
|
++ "," ++ show (nameUnique n)
|
|
|
|
++ "}"
|
|
|
|
where
|
|
|
|
nameSort
|
|
|
|
| isExternalName n = "external"
|
|
|
|
| isInternalName n = "internal"
|
|
|
|
| isSystemName n = "system"
|
|
|
|
| isWiredInName n = "wired-in"
|
|
|
|
| otherwise = "unknown" -- Shouldn't happen; these guards are exhaustive
|