summaryrefslogtreecommitdiff
path: root/utils/check-ppr/Main.hs
diff options
context:
space:
mode:
Diffstat (limited to 'utils/check-ppr/Main.hs')
-rw-r--r--utils/check-ppr/Main.hs219
1 files changed, 219 insertions, 0 deletions
diff --git a/utils/check-ppr/Main.hs b/utils/check-ppr/Main.hs
new file mode 100644
index 0000000000..c61b0e6d4c
--- /dev/null
+++ b/utils/check-ppr/Main.hs
@@ -0,0 +1,219 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE RankNTypes #-}
+
+import Data.Data hiding (Fixity)
+import Data.List
+import Bag
+import FastString
+import NameSet
+import SrcLoc
+import HsSyn
+import OccName hiding (occName)
+import GHC hiding (moduleName)
+import Var
+import DynFlags
+import Outputable hiding (space)
+import System.Environment( getArgs )
+import System.Exit
+import System.FilePath
+
+import qualified Data.ByteString as B
+import qualified Data.Map as Map
+
+main::IO()
+main = do
+ args <- getArgs
+ case args of
+ [libdir,fileName] -> testOneFile libdir fileName
+ _ -> putStrLn "invoke with the libdir and a file to parse."
+
+testOneFile :: FilePath -> String -> IO ()
+testOneFile libdir fileName = do
+ p <- parseOneFile libdir fileName
+ let
+ origAst = showAstData 0 (pm_parsed_source p)
+ pped = pragmas ++ "\n" ++ pp (pm_parsed_source p)
+ anns = pm_annotations p
+ pragmas = getPragmas anns
+
+ newFile = dropExtension fileName <.> "ppr" <.> takeExtension fileName
+ astFile = fileName <.> "ast"
+
+ writeFile astFile origAst
+ writeFile newFile pped
+
+ p' <- parseOneFile libdir newFile
+
+ let newAstStr = showAstData 0 (pm_parsed_source p')
+
+ if origAst == newAstStr
+ then do
+ -- putStrLn "ASTs matched"
+ exitSuccess
+ else do
+ putStrLn "AST Match Failed"
+ putStrLn "\n===================================\nOrig\n\n"
+ putStrLn origAst
+ putStrLn "\n===================================\nNew\n\n"
+ putStrLn newAstStr
+ exitFailure
+
+
+parseOneFile :: FilePath -> FilePath -> IO ParsedModule
+parseOneFile libdir fileName = do
+ let modByFile m =
+ case ml_hs_file $ ms_location m of
+ Nothing -> False
+ Just fn -> fn == fileName
+ runGhc (Just libdir) $ do
+ dflags <- getSessionDynFlags
+ let dflags2 = dflags `gopt_set` Opt_KeepRawTokenStream
+ _ <- setSessionDynFlags dflags2
+ addTarget Target { targetId = TargetFile fileName Nothing
+ , targetAllowObjCode = True
+ , targetContents = Nothing }
+ _ <- load LoadAllTargets
+ graph <- getModuleGraph
+ let
+ modSum = case filter modByFile graph of
+ [x] -> x
+ xs -> error $ "Can't find module, got:"
+ ++ show (map (ml_hs_file . ms_location) xs)
+ parseModule modSum
+
+getPragmas :: ApiAnns -> String
+getPragmas anns = pragmaStr
+ where
+ tokComment (L _ (AnnBlockComment s)) = s
+ tokComment (L _ (AnnLineComment s)) = s
+ tokComment _ = ""
+
+ comments = case Map.lookup noSrcSpan (snd anns) of
+ Nothing -> []
+ Just cl -> map tokComment $ sortLocated cl
+ pragmas = filter (\c -> isPrefixOf "{-#" c ) comments
+ pragmaStr = intercalate "\n" pragmas
+
+pp :: (Outputable a) => a -> String
+pp a = showPpr unsafeGlobalDynFlags a
+
+
+-- | Show a GHC AST with SrcSpan's blanked out, to avoid comparing locations,
+-- only structure
+showAstData :: Data a => Int -> a -> String
+showAstData n =
+ generic
+ `ext1Q` list
+ `extQ` string `extQ` fastString `extQ` srcSpan
+ `extQ` bytestring
+ `extQ` name `extQ` occName `extQ` moduleName `extQ` var `extQ` dataCon
+ `extQ` bagName `extQ` bagRdrName `extQ` bagVar `extQ` nameSet
+ `extQ` fixity
+ `ext2Q` located
+ where generic :: Data a => a -> String
+ generic t = indent n ++ "(" ++ showConstr (toConstr t)
+ ++ space (unwords (gmapQ (showAstData (n+1)) t)) ++ ")"
+ space "" = ""
+ space s = ' ':s
+ indent i = "\n" ++ replicate i ' '
+ string = show :: String -> String
+ fastString = ("{FastString: "++) . (++"}") . show
+ :: FastString -> String
+ bytestring = show :: B.ByteString -> String
+ list l = indent n ++ "["
+ ++ intercalate "," (map (showAstData (n+1)) l)
+ ++ "]"
+
+ name = ("{Name: "++) . (++"}") . showSDocDebug_ . ppr
+ :: Name -> String
+ occName = ("{OccName: "++) . (++"}") . OccName.occNameString
+ moduleName = ("{ModuleName: "++) . (++"}") . showSDoc_ . ppr
+ :: ModuleName -> String
+
+ srcSpan :: SrcSpan -> String
+ srcSpan _ss = "{ "++ "ss" ++"}"
+
+ var = ("{Var: "++) . (++"}") . showSDocDebug_ . ppr
+ :: Var -> String
+ dataCon = ("{DataCon: "++) . (++"}") . showSDoc_ . ppr
+ :: DataCon -> String
+
+ bagRdrName:: Bag (Located (HsBind RdrName)) -> String
+ bagRdrName = ("{Bag(Located (HsBind RdrName)): "++) . (++"}")
+ . list . bagToList
+ bagName :: Bag (Located (HsBind Name)) -> String
+ bagName = ("{Bag(Located (HsBind Name)): "++) . (++"}")
+ . list . bagToList
+ bagVar :: Bag (Located (HsBind Var)) -> String
+ bagVar = ("{Bag(Located (HsBind Var)): "++) . (++"}")
+ . list . bagToList
+
+ nameSet = ("{NameSet: "++) . (++"}") . list . nameSetElemsStable
+
+ fixity = ("{Fixity: "++) . (++"}") . showSDoc_ . ppr
+ :: Fixity -> String
+
+ located :: (Data b,Data loc) => GenLocated loc b -> String
+ located (L ss a) =
+ indent n ++ "("
+ ++ case cast ss of
+ Just (s :: SrcSpan) ->
+ srcSpan s
+ Nothing -> "nnnnnnnn"
+ ++ showAstData (n+1) a
+ ++ ")"
+
+showSDoc_ :: SDoc -> String
+showSDoc_ = showSDoc unsafeGlobalDynFlags
+
+showSDocDebug_ :: SDoc -> String
+showSDocDebug_ = showSDocDebug unsafeGlobalDynFlags
+
+-- ---------------------------------------------------------------------
+
+-- Copied from syb for the test
+
+
+-- | The type constructor for queries
+newtype Q q x = Q { unQ :: x -> q }
+
+-- | Extend a generic query by a type-specific case
+extQ :: ( Typeable a
+ , Typeable b
+ )
+ => (a -> q)
+ -> (b -> q)
+ -> a
+ -> q
+extQ f g a = maybe (f a) g (cast a)
+
+-- | Type extension of queries for type constructors
+ext1Q :: (Data d, Typeable t)
+ => (d -> q)
+ -> (forall e. Data e => t e -> q)
+ -> d -> q
+ext1Q def ext = unQ ((Q def) `ext1` (Q ext))
+
+
+-- | Type extension of queries for type constructors
+ext2Q :: (Data d, Typeable t)
+ => (d -> q)
+ -> (forall d1 d2. (Data d1, Data d2) => t d1 d2 -> q)
+ -> d -> q
+ext2Q def ext = unQ ((Q def) `ext2` (Q ext))
+
+-- | Flexible type extension
+ext1 :: (Data a, Typeable t)
+ => c a
+ -> (forall d. Data d => c (t d))
+ -> c a
+ext1 def ext = maybe def id (dataCast1 ext)
+
+
+
+-- | Flexible type extension
+ext2 :: (Data a, Typeable t)
+ => c a
+ -> (forall d1 d2. (Data d1, Data d2) => c (t d1 d2))
+ -> c a
+ext2 def ext = maybe def id (dataCast2 ext)