module Zeno.Flags ( ZenoFlags (..), readFlags, defaultFlags ) where import Prelude () import Zeno.Prelude import System.Console.GetOpt defaultIsabelleDir :: String defaultIsabelleDir = "isa" data ZenoFlags = ZenoFlags { flagVerboseProof :: !Bool, flagPrintCore :: !Bool, flagKeepModuleNames :: !Bool, flagSkipChecker :: !Bool, flagSkipSolver :: !Bool, flagSkipIsabelle :: !Bool, flagIsabelleAll :: !Bool, flagWebMode :: !Bool, flagIncludeDirs :: ![String], flagIsabelleDir :: !String, flagMatchWith :: ![String], flagHaskellFiles :: ![String], flagTimeout :: !Int } defaultFlags :: ZenoFlags defaultFlags = ZenoFlags { flagVerboseProof = False, flagPrintCore = False, flagKeepModuleNames = False, flagSkipChecker = False, flagSkipSolver = False, flagSkipIsabelle = False, flagIsabelleAll = False, flagWebMode = False, flagIncludeDirs = [], flagIsabelleDir = defaultIsabelleDir, flagMatchWith = [], flagHaskellFiles = [], flagTimeout = 0 } readFlags :: [String] -> ZenoFlags readFlags args | not (null errors) = error (concat errors ++ usage) | null (flagHaskellFiles flags) = error ("No Haskell filenames specified!\n\n" ++ usage) | otherwise = flags where header = "Usage: zeno [OPTION] [FILENAME]" examples = "\n\nExamples:" ++ "\n\nzeno *" ++ "\n Attempts to prove or disprove every property in every file " ++ "(ending in .hs or .lhs) in the current directory." ++ "\n\nzeno -m prop Test.hs" ++ "\n Attempts to prove or disprove every property " ++ "with the text \"prop\" in its name in the file \"Test.hs\" or its imports." ++ "\n\nzeno -S Test.hs" ++ "\n Disables the solver and hence runs Zeno as just a " ++ "counter-example finder on every property in \"Test.hs\"." ++ "\n\nzeno -CSa -o test Test.hs Test2.hs" ++ "\n Uses Zeno as a Haskell-to-Isabelle conversion tool on the code in " ++ "\"Test.hs\" and \"Test2.hs\", outputting it to the directory \"test\"" ++ "\n" usage = usageInfo (header ++ examples) options (flag_funs, [], errors) = getOpt (ReturnInOrder hsFile) options args hsFile n f | ".hs" `isSuffixOf` n || ".lhs" `isSuffixOf` n = f { flagHaskellFiles = n : flagHaskellFiles f } | otherwise = f flags = foldl' (flip ($)) defaultFlags flag_funs options :: [OptDescr (ZenoFlags -> ZenoFlags)] options = [ Option ['m'] ["match"] (ReqArg (\m f -> f { flagMatchWith = m : flagMatchWith f }) "TEXT") $ "Only consider properties which contain this string. " ++ "This argument may be given multiple times, in which case Zeno considers " ++ "properties containing any of the given strings.", {- Option ['v'] ["verbose"] (NoArg $ \f -> f { flagVerboseProof = True }) $ "Enables verbose Isabelle proof output, adding a " ++ "comment to every step that Zeno has made in constructing a proof.", -} Option ['c'] ["print-core"] (NoArg $ \f -> f { flagPrintCore = True }) $ "Prints the internal representation of any Haskell code that Zeno has loaded " ++ "along with any properties defined, then terminates Zeno. " ++ "This code Zeno uses has been through the GHC simplifier so may be " ++ "slightly different to the code you originally wrote. " ++ "If you are wondering why Zeno cannot work with a certain " ++ "function definition it might be worth checking how it came out here.", {- Option ['q'] ["qualify"] (NoArg $ \f -> f { flagKeepModuleNames = True }) $ "Stops Zeno from stripping modules from the beginning of names within your " ++ "program. Module names are removed by default for clarity, and will not affect " ++ "the Zeno system itself, but may cause naming clashes in the " ++ "Isabelle code that Zeno outputs.", -} Option ['C'] ["no-check"] (NoArg $ \f -> f { flagSkipChecker = True }) $ "Stops Zeno from running its counter-example finder (think SmallCheck but " ++ "worse) on properties. Not sure why you'd want to turn this off but " ++ "who am I to judge.", Option ['S'] ["no-solve"] (NoArg $ \f -> f { flagSkipSolver = True }) $ "Stops Zeno from attempting to prove properties. Might be useful if you " ++ "just wanted to run the counter-example finder.", Option ['I'] ["no-isa"] (NoArg $ \f -> f { flagSkipIsabelle = True }) $ "Stops Zeno from automatically invoking Isabelle on any programs or proofs that " ++ "it outputs. Maybe Isabelle is hanging (Zeno could probably put the simplifier " ++ "into a loop with the right input), maybe you'd rather just fire up Emacs " ++ "and run through the proofs yourself, or maybe you were too lazy to install " ++ "Isabelle in the first place.", Option ['a'] ["isa-all"] (NoArg $ \f -> f { flagIsabelleAll = True }) $ "Normally Zeno will only output functions to Isabelle if they are used " ++ "within proven properties. If you specify this option your entire program " ++ "will be printed to the Isabelle output file instead. " ++ "This feature is very experimental and the Isabelle output will often need " ++ "to be manually tweaked.", Option ['i'] ["include-dir"] (ReqArg (\d f -> f { flagIncludeDirs = d : flagIncludeDirs f }) "DIR") $ "Specify a directory to be included when loading Haskell code. " ++ "Essentially this is just passed as an -i parameter to GHC.", Option ['o'] ["isa-dir"] (ReqArg (\d f -> f { flagIsabelleDir = d }) "DIR") $ "Specify the directory where Zeno will output its generated Isabelle code. " ++ "Defaults to \"" ++ defaultIsabelleDir ++ "\"", Option ['t'] ["timeout"] (ReqArg (\t f -> f { flagTimeout = read t }) "SECS") $ "Specify a timeout for Zeno to run within; any number less than one is ignored.", Option [] ["tryzeno"] (NoArg $ \f -> f { flagWebMode = True }) $ "Formats the output for the TryZeno interface." ]