packages feed

language-python-test-0.5.8: src/RoundTrip.hs

import Language.Python.Common
import Language.Python.Version2 as V2
import Language.Python.Version3 as V3
import System.Exit
import System.Environment

data PythonVersion = Two | Three | Both
   deriving (Eq, Show)

data Comparison = ParseFailed String | Equal | NotEqual String String
type Parser = String -> String -> Either ParseError (ModuleSpan, [Token])

main :: IO ()
main = do
   args <- getArgs
   case args of
      (versionStr:inFile:_rest) ->
         case parseVersion versionStr of
            Nothing -> do
               putStrLn $ "Unknown Python version: " ++ versionStr
               exitFailure
            Just version -> do
               contents <- readFile inFile
               let parsers = pickParsers version
                   comparisons = [parseAndCompare p inFile contents | p <- parsers]
               test <- check comparisons
               if test then exitWith ExitSuccess else exitSuccess
      _other -> putStrLn "Incorrect command line. Expected: <2|3|n> inputFileName"

check :: [Comparison] -> IO Bool
check [] = return True -- must have all been equal
check (Equal:rest) = check rest
check (NotEqual s1 s2:_rest) = do
   doubleLine
   putStrLn "Round trip parse failed"
   doubleLine
   putStrLn "pretty1"
   line
   putStrLn s1
   doubleLine
   putStrLn "pretty2"
   line
   putStrLn s2
   return False
check (ParseFailed e:_rest) = do
   putStrLn "Parse failed with error: "
   putStrLn e
   return False

pickParsers :: PythonVersion -> [Parser]
pickParsers Two = [V2.parseModule]
pickParsers Three = [V3.parseModule]
pickParsers Both = [V2.parseModule, V3.parseModule]

parseAndCompare :: Parser -> FilePath -> String -> Comparison
parseAndCompare parser inFile contents =
   case parseAndPretty parser inFile contents of
      Left e -> ParseFailed $ prettyText e
      Right pretty1 ->
         case parseAndPretty parser "<pretty printed>" pretty1 of
            Left e -> ParseFailed $ prettyText e
            Right pretty2
               | pretty1 == pretty2 -> Equal
               | otherwise -> NotEqual pretty1 pretty2

line, doubleLine :: IO ()
line = putStrLn $ replicate 80 '-'
doubleLine = putStrLn $ replicate 80 '='

parseAndPretty :: Parser -> FilePath -> String -> Either ParseError String
parseAndPretty parser fileName contents =
   case parser contents fileName of
      Left e -> Left e
      Right (ast, _comments) -> Right (prettyText ast ++ "\n")

parseVersion :: String -> Maybe PythonVersion
parseVersion "2" = Just Two
parseVersion "3" = Just Three
parseVersion "n" = Just Both
parseVersion _other = Nothing