summaryrefslogtreecommitdiff
path: root/src/GF/Devel/Options.hs
diff options
context:
space:
mode:
authorbjorn <bjorn@bringert.net>2008-02-19 20:59:01 +0000
committerbjorn <bjorn@bringert.net>2008-02-19 20:59:01 +0000
commitb468482c3fc5406de4588463b10fb39e0c5e2528 (patch)
tree38d1da35976d1d3550179234f4952ef6add26aca /src/GF/Devel/Options.hs
parenta4bded9f3aa2cb4fe7344a8540a81ec7c1d81a63 (diff)
Some work on gf3/gfc command-line options.
Diffstat (limited to 'src/GF/Devel/Options.hs')
-rw-r--r--src/GF/Devel/Options.hs269
1 files changed, 269 insertions, 0 deletions
diff --git a/src/GF/Devel/Options.hs b/src/GF/Devel/Options.hs
new file mode 100644
index 000000000..14b598225
--- /dev/null
+++ b/src/GF/Devel/Options.hs
@@ -0,0 +1,269 @@
+module GF.Devel.Options
+ (
+ Err(..), -- FIXME: take from somewhere else
+
+ Options(..),
+ Mode(..), Phase(..), OutputFormat(..), Optimization(..),
+ parseOptions, helpMessage
+ ) where
+
+import Control.Monad
+import Data.Char (toLower)
+import Data.List
+import Data.Maybe
+import System.Console.GetOpt
+import System.FilePath
+
+
+
+
+
+usageHeader :: String
+usageHeader = unlines
+ ["Usage: gfc [OPTIONS] [FILE [...]]",
+ "",
+ "How each FILE is handled depends on the file name suffix:",
+ "",
+ ".gf Normal or old GF source, will be compiled.",
+ ".gfc Compiled GF source, will be loaded as is.",
+ ".gfe Example-based GF source, will be converted to .gf and compiled.",
+ ".ebnf Extended BNF format, will be converted to .gf and compiled.",
+ ".cf Context-free (BNF) format, will be converted to .gf and compiled.",
+ "",
+ "If multiple FILES are given, they must be normal GF source, .gfc or .gfe files.",
+ "For the other input formats, only one file can be given.",
+ "",
+ "Command-line options:"]
+
+
+helpMessage :: String
+helpMessage = usageInfo usageHeader optDescr
+
+-- Error monad
+
+type ErrorMsg = String
+
+data Err a = Ok a | Errors [ErrorMsg]
+ deriving (Read, Show, Eq)
+
+instance Monad Err where
+ return = Ok
+ fail e = Errors [e]
+ Ok a >>= f = f a
+ Errors s >>= f = Errors s
+
+errors :: [ErrorMsg] -> Err a
+errors = Errors
+
+-- Types
+
+data Mode = Version | Help | Interactive | Compiler
+ deriving (Show,Eq,Ord)
+
+data Phase = Preproc | Convert | Compile | Link
+ deriving (Show,Eq,Ord)
+
+data Encoding = UTF_8 | ISO_8859_1
+ deriving (Show,Eq,Ord)
+
+data OutputFormat = FmtGFCC | FmtJS
+ deriving (Show,Eq,Ord)
+
+data Optimization = OptStem | OptCSE
+ deriving (Show,Eq,Ord)
+
+data Warning = WarnMissingLincat
+ deriving (Show,Eq,Ord)
+
+data Dump = DumpRebuild | DumpExtend | DumpRename | DumpTypecheck | DumpRefresh | DumpOptimize | DumpCanon
+ deriving (Show,Eq,Ord)
+
+data ModuleOptions = ModuleOptions {
+ optPreprocessors :: [String],
+ optEncoding :: Encoding,
+ optOptimizations :: [Optimization],
+ optLibraryPath :: [FilePath],
+ optSpeechLanguage :: Maybe String,
+ optBuildParser :: Bool,
+ optWarnings :: [Warning],
+ optDump :: [Dump]
+ }
+ deriving (Show)
+
+data Options = Options {
+ optMode :: Mode,
+ optStopAfterPhase :: Phase,
+ optVerbosity :: Int,
+ optShowCPUTime :: Bool,
+ optEmitGFO :: Bool,
+ optGFODir :: FilePath,
+ optOutputFormats :: [OutputFormat],
+ optOutputName :: Maybe String,
+ optOutputFile :: Maybe FilePath,
+ optOutputDir :: FilePath,
+ optForceRecomp :: Bool,
+ optProb :: Bool,
+ optStartCategory :: Maybe String,
+ optModuleOptions :: ModuleOptions
+ }
+ deriving (Show)
+
+-- Option parsing
+
+parseOptions :: [String] -> Err (Options, [FilePath])
+parseOptions args = case errs of
+ [] -> do o <- foldM (\o f -> f o) defaultOptions opts
+ return (o, files)
+ _ -> errors errs
+ where (opts, files, errs) = getOpt RequireOrder optDescr args
+
+parseModuleFlags :: Options -> [(String,String)] -> Err ModuleOptions
+parseModuleFlags opts flags = foldr setOpt (optModuleOptions opts) moduleOptDescr
+ where
+ setOpt (Option _ ss arg _) d
+ | null values = d
+ | otherwise = case arg of
+ NoArg a ->
+ ReqArg (String -> a) _ ->
+OptArg (Maybe String -> a) String
+last values
+ where values = [v | (k,v) <- flags, k `elem` ss ]
+
+-- Default options
+
+defaultModuleOptions :: ModuleOptions
+defaultModuleOptions = ModuleOptions {
+ optPreprocessors = [],
+ optEncoding = ISO_8859_1,
+ optOptimizations = [OptStem,OptCSE],
+ optLibraryPath = [],
+ optSpeechLanguage = Nothing,
+ optBuildParser = True,
+ optWarnings = [],
+ optDump = []
+ }
+
+defaultOptions :: Options
+defaultOptions = Options {
+ optMode = Interactive,
+ optStopAfterPhase = Link,
+ optVerbosity = 1,
+ optShowCPUTime = False,
+ optEmitGFO = True,
+ optGFODir = ".",
+ optOutputFormats = [FmtGFCC],
+ optOutputName = Nothing,
+ optOutputFile = Nothing,
+ optOutputDir = ".",
+ optForceRecomp = False,
+ optProb = False,
+ optStartCategory = Nothing,
+ optModuleOptions = defaultModuleOptions
+ }
+
+-- Option descriptions
+
+moduleOptDescr :: [OptDescr (ModuleOptions -> Err ModuleOptions)]
+moduleOptDescr =
+ [
+ Option ['i'] [] (ReqArg addLibDir "DIR") "Add DIR to the library search path.",
+ Option [] ["path"] (ReqArg setLibPath "DIR:DIR:...") "Set the library search path.",
+ Option [] ["preproc"] (ReqArg preproc "CMD")
+ (unlines ["Use CMD to preprocess input files.",
+ "Multiple preprocessors can be used by giving this option multiple times."]),
+ Option [] ["stem"] (onOff (optimize OptStem) True) "Perform stem-suffix analysis (default on).",
+ Option [] ["cse"] (onOff (optimize OptCSE) True) "Perform common sub-expression elimination (default on).",
+ Option [] ["parser"] (onOff parser True) "Build parser (default on).",
+ Option [] ["language"] (ReqArg language "LANG") "Set the speech language flag to LANG in the generated grammar."
+ ]
+ where
+ addLibDir x o = return $ o { optLibraryPath = x:optLibraryPath o }
+ setLibPath x o = return $ o { optLibraryPath = splitSearchPath x }
+ preproc x o = return $ o { optPreprocessors = optPreprocessors o ++ [x] }
+ optimize x b o = return $ o { optOptimizations = (if b then (x:) else delete x) (optOptimizations o) }
+ parser x o = return $ o { optBuildParser = x }
+ language x o = return $ o { optSpeechLanguage = Just x }
+
+optDescr :: [OptDescr (Options -> Err Options)]
+optDescr =
+ [
+ Option ['E'] [] (NoArg (phase Preproc)) "Stop after preprocessing (with --preproc).",
+ Option ['C'] [] (NoArg (phase Convert)) "Stop after conversion to .gf.",
+ Option ['c'] [] (NoArg (phase Compile)) "Stop after compiling to .gfo.",
+ Option ['V'] ["version"] (NoArg (mode Version)) "Display GF version number.",
+ Option ['?','h'] ["help"] (NoArg (mode Help)) "Show help message.",
+ Option ['v'] ["verbose"] (OptArg verbosity "N") "Set verbosity (default 1). -v alone is the same as -v 3.",
+ Option ['q'] ["quiet"] (NoArg (verbosity (Just "0"))) "Quiet, same as -v 0.",
+ Option [] ["batch"] (NoArg (mode Compiler)) "Run in batch compiler mode.",
+ Option [] ["interactive"] (NoArg (mode Interactive)) "Run in interactive mode (default).",
+ Option [] ["cpu"] (NoArg (cpu True)) "Show compilation CPU time statistics.",
+ Option [] ["no-cpu"] (NoArg (cpu False)) "Don't show compilation CPU time statistics (default).",
+ Option [] ["emit-gfo"] (NoArg (emitGFO True)) "Create .gfo files (default).",
+ Option [] ["no-emit-gfo"] (NoArg (emitGFO False)) "Do not create .gfo files.",
+ Option [] ["gfo-dir"] (ReqArg gfoDir "DIR") "Directory to put .gfo files in (default = '.').",
+ Option ['f'] ["output-format"] (ReqArg outFmt "FMT")
+ (unlines ["Output format. FMT can be one of:",
+ "Multiple concrete: gfcc (default), gar, js, ...",
+ "Single concrete only: cf, bnf, lbnf, gsl, srgs_xml, srgs_abnf, ...",
+ "Abstract only: haskell, ..."]),
+ Option ['n'] ["output-name"] (ReqArg outName "NAME")
+ ("Use NAME as the name of the output. This is used in the output file names, "
+ ++ "with suffixes depending on the formats, and, when relevant, "
+ ++ "internally in the output."),
+ Option ['o'] ["output-file"] (ReqArg outFile "FILE")
+ "Save output in FILE (default is out.X, where X depends on output format.",
+ Option ['D'] ["output-dir"] (ReqArg outDir "DIR")
+ "Save output files (other than .gfc files) in DIR.",
+ Option [] ["src","force-recomp"] (NoArg (forceRecomp True))
+ "Always recompile from source, i.e. disable recompilation checking.",
+ Option [] ["prob"] (NoArg (prob True)) "Read probabilities from '--# prob' pragmas.",
+ Option [] ["startcat"] (ReqArg startcat "CAT") "Use CAT as the start category in the generated grammar."
+ ] ++ map (fmap onModuleOptions) moduleOptDescr
+ where phase x o = return $ o { optStopAfterPhase = x }
+ mode x o = return $ o { optMode = x }
+ verbosity mv o = case mv of
+ Nothing -> return $ o { optVerbosity = 3 }
+ Just v -> case reads v of
+ [(i,"")] | i >= 0 -> return $ o { optVerbosity = i }
+ _ -> fail $ "Bad verbosity: " ++ show v
+ cpu x o = return $ o { optShowCPUTime = x }
+ emitGFO x o = return $ o { optEmitGFO = x }
+ gfoDir x o = return $ o { optGFODir = x }
+ outFmt x o = readOutputFormat x >>= \f ->
+ return $ o { optOutputFormats = optOutputFormats o ++ [f] }
+ outName x o = return $ o { optOutputName = Just x }
+ outFile x o = return $ o { optOutputFile = Just x }
+ outDir x o = return $ o { optOutputDir = x }
+ forceRecomp x o = return $ o { optForceRecomp = x }
+ prob x o = return $ o { optProb = x }
+ startcat x o = return $ o { optStartCategory = Just x }
+
+onModuleOptions :: Monad m => (ModuleOptions -> m ModuleOptions) -> Options -> m Options
+onModuleOptions f o = do mo' <- f (optModuleOptions o)
+ return $ o { optModuleOptions = mo' }
+
+instance Functor OptDescr where
+ fmap f (Option cs ss d s) = Option cs ss (fmap f d) s
+
+instance Functor ArgDescr where
+ fmap f (NoArg x) = NoArg (f x)
+ fmap f (ReqArg g s) = ReqArg (f . g) s
+ fmap f (OptArg g s) = OptArg (f . g) s
+
+outputFormats :: [(String,OutputFormat)]
+outputFormats =
+ [("gfcc", FmtGFCC),
+ ("js", FmtJS)]
+
+onOff :: Monad m => (Bool -> (a -> m a)) -> Bool -> ArgDescr (a -> m a)
+onOff f def = OptArg g "[on,off]"
+ where g ma x = do b <- maybe (return def) readOnOff ma
+ f b x
+ readOnOff x = case map toLower x of
+ "on" -> return True
+ "off" -> return False
+ _ -> fail $ "Expected [on,off], got: " ++ show x
+
+readOutputFormat :: Monad m => String -> m OutputFormat
+readOutputFormat s =
+ maybe (fail $ "Unknown output format: " ++ show s) return $ lookup s outputFormats