module Test.SBench.File.Parser
( getMetaInfo
, getWholeFile
) where
import Text.Parsec.String ( Parser(..), parseFromFile)
import Text.Parsec.Error ( ParseError )
import Text.Parsec.Combinator ( manyTill, many1, sepBy, count )
import Text.Parsec.Prim ( many, (<?>), (<|>), try )
import Text.Parsec.Char ( anyChar, spaces, string, newline, digit, char )
import System.FilePath ( FilePath )
import Test.SBench.File.Types ( MetaInfo(..), Range(..) )
import Test.SBench.Options ( EvalMod (..) )
getMetaInfo :: FilePath -> IO (MetaInfo Double Double)
getMetaInfo file = do
emi <- parseFromFile metaInfoParser file
case emi of
Left err -> error $ show err
Right mi -> return mi
getWholeFile :: FilePath -> IO (MetaInfo Double Double, [(Double,Double)])
getWholeFile file = do
emi <- parseFromFile wholeFileParser file
case emi of
Left err -> error $ show err
Right mi -> return mi
wholeFileParser :: Parser (MetaInfo Double Double, [(Double,Double)])
wholeFileParser = do
mi <- metaInfoParser
dat <- dataParser
return (mi, dat)
metaInfoParser :: Parser (MetaInfo Double Double)
metaInfoParser = do
hs <- many $ try headerLineParser
v <- versionParser
pt <- graphTitleParser
alg <- algNameParser
gen <- genNameParser
evMod <- evalModParser
prs <- graphRangesParser
bopts <- buildOptsParser
eopts <- exeOptsParser
return MetaInfo {
header = hs
, sbenchVersion = v
, miGraphTitle = pt
, miAlgName = alg
, miGenName = gen
, evalMod = evMod
, graphRanges = prs
, buildOptions = bopts
, exeOptions = eopts
}
headerLineParser :: Parser String
headerLineParser = do
commentLine <?> "HeaderLineParser: Expected Line to start with '#'.\n"
spaces
string "header: "
manyTill anyChar newline
versionParser :: Parser String
versionParser = do
commentLine <?> "versionParser: Expected Line to start with '#'.\n"
spaces
string "SBench version:" <?> "expected SBench version number"
spaces
andNewLine (vnumParser <?> "Invalid SBench version number.")
where
vnumParser :: Parser String
vnumParser = do main <- many1 digit
subs <- many subnum
return $ foldl (++) main subs
subnum = do char '.'
ds <- many1 digit
return $ '.' : ds
testNameParser :: Parser String
testNameParser = do
commentLine <?> "testNameParser: Expected Line to start with '#'.\n"
spaces
string "test name:" <?> "expected test name"
spaces
andNewLine wordParser
genDimParser :: Parser Int
genDimParser = do
commentLine <?> "genDimParser: Expected Line to start with '#'.\n"
spaces
string "number of generators:"
spaces
snum <- andNewLine $ many1 digit
return ((read snum) :: Int)
graphTitleParser :: Parser String
graphTitleParser = do
commentLine <?> "graphTitleParser: Expected Line to start with '#'.\n"
spaces
string "graph title:" <?> "expected graph title"
spaces
andNewLine wordParser
algNameParser :: Parser String
algNameParser = do
commentLine <?> "algNameParser: Expected Line to start with '#'.\n"
spaces
string "tested algorithm: " <?> "expected name of tested algorithm"
spaces
andNewLine wordParser
genNameParser :: Parser (Either String String)
genNameParser = do
commentLine <?> "genNameParser: Expected Line to start with '#'.\n"
spaces
string "input"
(try inputParser) <|> inputGenParser
where inputParser = do string ": "
spaces
n <- andNewLine wordParser
return (Right n)
inputGenParser = do string " generator: " <?> "expected name of the input generator or input"
spaces
n <- andNewLine wordParser
return (Left n)
evalModParser :: Parser (Maybe EvalMod)
evalModParser = do
commentLine <?> "evalModParser: Expected Line to start with '#'.\n"
spaces
string "evaluation mode: " <?> "expected evaluation mode"
spaces
andNewLine (evMod <|> return Nothing)
where
evMod = ((string "nf" >> return (Just NF)) <|> (string "whnf" >> return (Just WHNF)))
buildOptsParser :: Parser String
buildOptsParser = do
commentLine <?> "buildOptsParser: Expected Line to start with '#'.\n"
spaces
string "build options: " <?> "expected build options"
spaces
andNewLine wordParser
exeOptsParser :: Parser String
exeOptsParser = do
commentLine <?> "exeOptsParser: Expected Line to start with '#'.\n"
spaces
string "execution options: " <?> "expected execution options"
spaces
andNewLine wordParser
graphRangesParser :: Parser (Range Double, Range Double)
graphRangesParser = do
commentLine <?> "graphRangesParser: Expected Line to start with '#'.\n"
spaces
string "graph ranges:" <?> "expected graph ranges"
spaces
let p = try autoParser <|> manParser
andNewLine $ pairParser p p
where
autoParser :: Parser (Range Double)
autoParser = do string "Auto"
return AutoRange
manParser :: Parser (Range Double)
manParser = do
r <- pairParser doubleParser doubleParser
return $ ManRange r
pairParser :: Parser a -> Parser b -> Parser (a, b)
pairParser p1 p2 = do
rmAllWhiteParser '('
c1 <- p1
rmAllWhiteParser ','
c2 <- p2
rmLeadingWhiteParser ')'
return (c1, c2)
doubleParser :: Parser Double
doubleParser = do
i <- many digit
f <- (char '.' >> many digit) <|> return "0"
e <- do char 'e'
s <- string "+" <|> string "-" <|> return "+"
e <- many1 digit
return $ "e" ++ s ++ e
<|> return ""
return $ (read (i ++ "." ++ f ++ e) :: Double)
intParser :: Parser Int
intParser = do
i <- many1 digit <?> "expected an integer"
return (read i :: Int)
axisLabelParser :: Parser [String]
axisLabelParser = do
commentLine <?> "axisLabelParser: Expected Line to start with '#'.\n"
spaces
string "axis labels:" <?> "expected axis labels"
spaces
andNewLine $ listParser wordParser
rmAllWhiteParser :: Char -> Parser ()
rmAllWhiteParser c = spaces >> char c >> spaces
rmLeadingWhiteParser :: Char -> Parser ()
rmLeadingWhiteParser c = spaces >> char c >> return ()
listParser :: Parser a -> Parser [a]
listParser p = do
rmAllWhiteParser '['
ret <- sepBy p (rmAllWhiteParser ',')
rmLeadingWhiteParser ']'
return ret
wordParser :: Parser String
wordParser = char '"' >> manyTill anyChar (char '"')
andNewLine :: Parser a -> Parser a
andNewLine p = do
ret <- p
manyTill anyChar newline
return ret
commentLine :: Parser ()
commentLine = many1 (char '#') >> return ()
dataParser :: Parser [(Double, Double)]
dataParser = many $ oneDataLineParser
oneDataLineParser :: Parser (Double, Double)
oneDataLineParser = do
gens <- spaces >> doubleParser
rt <- andNewLine $ spaces >> doubleParser
return (gens, rt)