{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-} -- | -- Suite parses the testsuite folder and creates benchmarks module Suite ( readBenches, BenchSuiteCase(..), stretch, runBench ) where import qualified Data.Text as T (unpack) import qualified Data.Text.IO as TIO (readFile) import System.Directory (getCurrentDirectory, listDirectory, doesDirectoryExist) import System.FilePath (FilePath, (), takeExtension, takeBaseName, takeDirectory) import Text.XML.HXT.DOM.TypeDefs (XmlTree) import Control.DeepSeq (NFData) import GHC.Generics (Generic) import Data.Int (Int64) import Patterns (Refs, hasRecursion) import Json (JsonTree, decodeJSON) import Xml (decodeXML) import Parser (parseGrammar) import qualified Relapse runBench :: BenchSuiteCase -> IO Int runBench (BenchSuiteCase _ g (XMLDatas inputs)) = return $ length $ Relapse.filter (fromGrammar g) inputs runBench (BenchSuiteCase _ g (JsonDatas inputs)) = return $ length $ Relapse.filter (fromGrammar g) inputs readBenches :: IO [BenchSuiteCase] readBenches = do { path <- benchPath; exists <- doesDirectoryExist path; if exists then do { jsondirs <- ls $ path "json"; -- TODO create xml benches in testsuite -- xmldirs <- ls $ path "xml"; -- xmlBenches <- mapM readXMLBench xmldirs; jsonBenches <- mapM readJsonBench jsondirs; return $ filter (\(BenchSuiteCase _ g _) -> not (hasRecursion $ fromGrammar g)) jsonBenches } else return [] } data BenchSuiteCase = BenchSuiteCase { benchname :: String , grammar :: String , input :: EncodedData } deriving (Show, Generic, NFData) data EncodedData = XMLDatas [[XmlTree]] | JsonDatas [[JsonTree]] deriving (Show, Generic, NFData) stretch :: BenchSuiteCase -> Int64 -> IO BenchSuiteCase stretch (BenchSuiteCase name g (XMLDatas xs)) n = return $ BenchSuiteCase name g $ XMLDatas $ stretch' (fromIntegral n) xs stretch (BenchSuiteCase name g (JsonDatas xs)) n = return $ BenchSuiteCase name g $ JsonDatas $ stretch' (fromIntegral n) xs stretch' :: Int -> [a] -> [a] stretch' n xs | length xs > n = take n xs | otherwise = xs ++ stretch' (n - length xs) xs must :: Either String a -> a must e = case e of (Left l) -> error l (Right r) -> r getRelapse :: [FilePath] -> FilePath getRelapse paths = head $ filter (\fname -> takeExtension fname == ".txt" && takeBaseName fname == "relapse") paths filesWithExt :: String -> [FilePath] -> [FilePath] filesWithExt ext = filter (\fname -> takeExtension fname == ext && takeBaseName fname /= "relapse") fromGrammar :: String -> Refs fromGrammar s = case parseGrammar s of (Left err) -> error $ "given input: <" ++ s ++ "> got parse error: " ++ show err (Right r) -> r readFileStrict :: FilePath -> IO String readFileStrict = fmap T.unpack . TIO.readFile readJsonBench :: FilePath -> IO BenchSuiteCase readJsonBench path = do { files <- ls path; grammarData <- readFileStrict $ getRelapse files; jsonDatas <- mapM readFileStrict $ filesWithExt ".json" files; return $ BenchSuiteCase (takeBaseName path ++ "Json") grammarData (JsonDatas $ map (must . decodeJSON) jsonDatas) } readXMLBench :: FilePath -> IO BenchSuiteCase readXMLBench path = do { files <- ls path; grammarData <- readFileStrict $ getRelapse files; xmlDatas <- mapM readFileStrict $ filesWithExt ".xml" files; return $ BenchSuiteCase (takeBaseName path ++ "XML") grammarData (XMLDatas $ map decodeXML xmlDatas) } ls :: FilePath -> IO [FilePath] ls path = do { dirs <- listDirectory path; return $ map (path ) dirs } benchPath :: IO FilePath benchPath = do { path <- getCurrentDirectory; return $ takeDirectory path "testsuite" "relapse" "benches" }