summaryrefslogtreecommitdiff
path: root/src-3.0/GF/Infra/Option.hs
diff options
context:
space:
mode:
authorbjorn <bjorn@bringert.net>2008-05-28 15:10:36 +0000
committerbjorn <bjorn@bringert.net>2008-05-28 15:10:36 +0000
commit3fd1f5652a3af22e90a040a821d244a91a3553a0 (patch)
tree15225df670e1fb1c55f4a9eb1ca45eae7952061f /src-3.0/GF/Infra/Option.hs
parent1bc74749aa7a9ec6ecfced68c0cdf38f43c7f9ef (diff)
Switch to new options handling.
This changes lots of stuff, let me know if it broke anything. Comments: - We use a local hacked version of GetOpt that allows long forms of commands to start with a single dash. This breaks other parts of GetOpt. For example, arguments to short options now require a =, and does not allo pace after the option character. - The new command parsing is currently only used for the program command line, pragmas and the arguments for the 'i' shell command. - I made a quick hack for the options for showTerm, which currently makes it impossible to use the print style flags for cc. This will be replaced by a facility for parsing command-specific options. - The verbosity handling is broken in some places. I will fix that in a later patch.
Diffstat (limited to 'src-3.0/GF/Infra/Option.hs')
-rw-r--r--src-3.0/GF/Infra/Option.hs797
1 files changed, 443 insertions, 354 deletions
diff --git a/src-3.0/GF/Infra/Option.hs b/src-3.0/GF/Infra/Option.hs
index a44cd9db8..dc795e597 100644
--- a/src-3.0/GF/Infra/Option.hs
+++ b/src-3.0/GF/Infra/Option.hs
@@ -1,375 +1,464 @@
-----------------------------------------------------------------------
--- |
--- Module : Option
--- Maintainer : AR
--- Stability : (stable)
--- Portability : (portable)
---
--- > CVS $Date: 2005/11/14 16:03:41 $
--- > CVS $Author: aarne $
--- > CVS $Revision: 1.34 $
---
--- Options and flags used in GF shell commands and files.
---
--- The types 'Option' and 'Options' should be kept abstract, but:
---
--- - The constructor 'Opt' is used in "ShellCommands" and "GrammarToSource"
---
--- - The constructor 'Opts' us udes in "API", "Shell" and "ShellCommands"
------------------------------------------------------------------------------
-
-module GF.Infra.Option where
-
-import Data.List (partition)
-import Data.Char (isDigit)
-
--- * all kinds of options, to be kept abstract
-
-newtype Option = Opt (String,[String]) deriving (Eq,Show,Read)
-newtype Options = Opts [Option] deriving (Eq,Show,Read)
+module GF.Infra.Option
+ (
+ -- * Option types
+ Options, ModuleOptions,
+ Flags(..), ModuleFlags(..),
+ Mode(..), Phase(..), Encoding(..), OutputFormat(..), Optimization(..),
+ Dump(..), Printer(..), Recomp(..),
+ -- * Option parsing
+ parseOptions, parseModuleOptions,
+ -- * Option pretty-printing
+ moduleOptionsGFO,
+ -- * Option manipulation
+ addOptions, concatOptions, noOptions,
+ moduleOptions,
+ addModuleOptions, concatModuleOptions, noModuleOptions,
+ helpMessage,
+ -- * Checking options
+ flag, moduleFlag,
+ -- * Convenience methods for checking options
+ beVerbose, beSilent,
+ dump
+ ) where
+
+import Control.Monad
+import Data.Char (toLower)
+import Data.List
+import Data.Maybe
+import GF.Infra.GetOpt
+--import System.Console.GetOpt
+import System.FilePath
+
+import GF.Data.ErrM
+
+
+
+
+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.",
+ ".gfo 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, .gfo or .gfe files.",
+ "For the other input formats, only one file can be given.",
+ "",
+ "Command-line options:"]
+
+
+helpMessage :: String
+helpMessage = usageInfo usageHeader optDescr
+
+
+-- FIXME: do we really want multi-line errors?
+errors :: [String] -> Err a
+errors = fail . unlines
+
+-- Types
+
+data Mode = ModeVersion | ModeHelp | ModeInteractive | ModeCompiler
+ 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 | FmtJavaScript | FmtHaskell | FmtHaskellGADT
+ deriving (Eq,Ord)
+
+data Optimization = OptStem | OptCSE | OptExpand | OptParametrize | OptValues
+ deriving (Show,Eq,Ord)
+
+data Warning = WarnMissingLincat
+ deriving (Show,Eq,Ord)
+
+data Dump = DumpRebuild | DumpExtend | DumpRename | DumpTypeCheck | DumpRefresh | DumpOptimize | DumpCanon
+ deriving (Show,Eq,Ord)
+
+-- | Pretty-printing options
+data Printer = PrinterStrip -- ^ Remove name qualifiers.
+ deriving (Show,Eq,Ord)
+
+data Recomp = AlwaysRecomp | RecompIfNewer | NeverRecomp
+ deriving (Show,Eq,Ord)
+
+data ModuleFlags = ModuleFlags {
+ optName :: Maybe String,
+ optAbsName :: Maybe String,
+ optCncName :: Maybe String,
+ optResName :: Maybe String,
+ optPreprocessors :: [String],
+ optEncoding :: Encoding,
+ optOptimizations :: [Optimization],
+ optLibraryPath :: [FilePath],
+ optStartCat :: Maybe String,
+ optSpeechLanguage :: Maybe String,
+ optLexer :: Maybe String,
+ optUnlexer :: Maybe String,
+ optBuildParser :: Bool,
+ optWarnings :: [Warning],
+ optDump :: [Dump]
+ }
+ deriving (Show)
+
+data Flags = Flags {
+ optMode :: Mode,
+ optStopAfterPhase :: Phase,
+ optVerbosity :: Int,
+ optShowCPUTime :: Bool,
+ optEmitGFO :: Bool,
+ optGFODir :: FilePath,
+ optOutputFormats :: [OutputFormat],
+ optOutputFile :: Maybe FilePath,
+ optOutputDir :: Maybe FilePath,
+ optRecomp :: Recomp,
+ optPrinter :: [Printer],
+ optProb :: Bool,
+ optRetainResource :: Bool,
+ optModuleFlags :: ModuleFlags
+ }
+ deriving (Show)
+
+newtype Options = Options (Flags -> Flags)
+
+instance Show Options where
+ show (Options o) = show (o defaultFlags)
+
+newtype ModuleOptions = ModuleOptions (ModuleFlags -> ModuleFlags)
+
+-- Option parsing
+
+parseOptions :: [String] -> Err (Options, [FilePath])
+parseOptions args
+ | not (null errs) = errors errs
+ | otherwise = do opts <- liftM concatOptions $ sequence optss
+ return (opts, files)
+ where (optss, files, errs) = getOpt RequireOrder optDescr args
+
+parseModuleOptions :: [String] -> Err ModuleOptions
+parseModuleOptions args
+ | not (null errs) = errors errs
+ | not (null files) = errors $ map ("Non-option among module options: " ++) files
+ | otherwise = liftM concatModuleOptions $ sequence flags
+ where (flags, files, errs) = getOpt RequireOrder moduleOptDescr args
+
+-- Showing options
+
+-- | Pretty-print the module options that are preserved in .gfo files.
+moduleOptionsGFO :: ModuleOptions -> [(String,String)]
+moduleOptionsGFO (ModuleOptions o) =
+ maybe [] (\l -> [("language",l)]) (optSpeechLanguage mfs)
+ where mfs = o defaultModuleFlags
+
+
+-- Option manipulation
noOptions :: Options
-noOptions = Opts []
-
--- | simple option -o
-iOpt :: String -> Option
-iOpt o = Opt (o,[])
-
--- | option with argument -o=a
-aOpt :: String -> String -> Option
-aOpt o a = Opt (o,[a])
-
-iOpts :: [Option] -> Options
-iOpts = Opts
-
--- | value of option argument
-oArg :: String -> String
-oArg s = s
-
-oElem :: Option -> Options -> Bool
-oElem o (Opts os) = elem o os
-
-eqOpt :: String -> Option -> Bool
-eqOpt s (Opt (o, [])) = s == o
-eqOpt s _ = False
-
-type OptFun = String -> Option
-type OptFunId = String
-
-getOptVal :: Options -> OptFun -> Maybe String
-getOptVal (Opts os) fopt =
- case [a | opt@(Opt (o,[a])) <- os, opt == fopt a] of
- a:_ -> Just a
- _ -> Nothing
+noOptions = Options id
-isSetFlag :: Options -> OptFun -> Bool
-isSetFlag (Opts os) fopt =
- case [a | opt@(Opt (o,[a])) <- os, opt == fopt a] of
- a:_ -> True
- _ -> False
-
-getOptInt :: Options -> OptFun -> Maybe Int
-getOptInt opts f = do
- s <- getOptVal opts f
- if (not (null s) && all isDigit s) then return (read s) else Nothing
-
-optIntOrAll :: Options -> OptFun -> [a] -> [a]
-optIntOrAll opts f = case getOptInt opts f of
- Just i -> take i
- _ -> id
-
-optIntOrN :: Options -> OptFun -> Int -> Int
-optIntOrN opts f n = case getOptInt opts f of
- Just i -> i
- _ -> n
-
-optIntOrOne :: Options -> OptFun -> Int
-optIntOrOne opts f = optIntOrN opts f 1
-
-changeOptVal :: Options -> OptFun -> String -> Options
-changeOptVal os f x =
- addOption (f x) $ maybe os (\y -> removeOption (f y) os) $ getOptVal os f
-
-addOption :: Option -> Options -> Options
-addOption o (Opts os) = iOpts (o:os)
-
-addOptions :: Options -> Options -> Options
-addOptions (Opts os) os0 = foldr addOption os0 os
+addOptions :: Options -- ^ Existing options.
+ -> Options -- ^ Options to add (these take preference).
+ -> Options
+addOptions (Options o1) (Options o2) = Options (o2 . o1)
concatOptions :: [Options] -> Options
concatOptions = foldr addOptions noOptions
-removeOption :: Option -> Options -> Options
-removeOption o (Opts os) = iOpts (filter (/=o) os)
-
-removeOptions :: Options -> Options -> Options
-removeOptions (Opts os) os0 = foldr removeOption os0 os
+moduleOptions :: ModuleOptions -> Options
+moduleOptions (ModuleOptions f) = Options (\o -> o { optModuleFlags = f (optModuleFlags o) })
-options :: [Option] -> Options
-options = foldr addOption noOptions
+addModuleOptions :: ModuleOptions -- ^ Existing options.
+ -> ModuleOptions -- ^ Options to add (these take preference).
+ -> ModuleOptions
+addModuleOptions (ModuleOptions o1) (ModuleOptions o2) = ModuleOptions (o2 . o1)
-unionOptions :: Options -> Options -> Options
-unionOptions (Opts os) (Opts os') = Opts (os ++ os')
+concatModuleOptions :: [ModuleOptions] -> ModuleOptions
+concatModuleOptions = foldr addModuleOptions noModuleOptions
--- * parsing options, with prefix pre (e.g. \"-\")
+noModuleOptions :: ModuleOptions
+noModuleOptions = ModuleOptions id
-getOptions :: String -> [String] -> (Options, [String])
-getOptions pre inp = let
- (os,rest) = span (isOption pre) inp -- options before args
- in
- (Opts (map (pOption pre) os), rest)
+flag :: (Flags -> a) -> Options -> a
+flag f (Options o) = f (o defaultFlags)
-pOption :: String -> String -> Option
-pOption pre s = case span (/= '=') (drop (length pre) s) of
- (f,_:a) -> aOpt f a
- (o,[]) -> iOpt o
+moduleFlag :: (ModuleFlags -> a) -> Options -> a
+moduleFlag f = flag (f . optModuleFlags)
-isOption :: String -> String -> Bool
-isOption pre = (==pre) . take (length pre)
--- * printing options, without prefix
-
-prOpt :: Option -> String
-prOpt (Opt (s,[])) = s
-prOpt (Opt (s,xs)) = s ++ "=" ++ concat xs
-
-prOpts :: Options -> String
-prOpts (Opts os) = unwords $ map prOpt os
-
--- * a suggestion for option names
+{-
--- ** parsing
+parseModuleFlags :: Options -> [(String,Maybe String)] -> Err ModuleOptions
+parseModuleFlags opts flags =
+ mapM (uncurry (findFlag moduleOptDescr)) flags >>= foldM (flip ($)) (optModuleOptions opts)
+
+findFlag :: Monad m => [OptDescr a] -> String -> Maybe String -> m a
+findFlag opts n mv =
+ case filter (`flagMatches` n) opts of
+ [] -> fail $ "Unknown option: " ++ n
+ [opt] -> flagValue opt n mv
+ _ -> fail $ n ++ " matches multiple options."
+
+flagMatches :: OptDescr a -> String -> Bool
+flagMatches (Option cs ss _ _) n = n `elem` (map (:[]) cs ++ ss)
+
+flagValue :: Monad m => OptDescr a -> String -> Maybe String -> m a
+flagValue (Option _ _ arg _) n mv =
+ case (arg, mv) of
+ (NoArg x, Nothing) -> return x
+ (NoArg _, Just _ ) -> fail $ "Option " ++ n ++ " does not take a value."
+ (ReqArg _ _, Nothing) -> fail $ "Option " ++ n ++ " requires a value."
+ (ReqArg f _, Just x ) -> return (f x)
+ (OptArg f _, mx ) -> return (f mx)
-strictParse, forgiveParse, ignoreParse, literalParse, rawParse, firstParse :: Option
--- | parse as term instead of string
-dontParse :: Option
+-}
-strictParse = iOpt "strict"
-forgiveParse = iOpt "n"
-ignoreParse = iOpt "ign"
-literalParse = iOpt "lit"
-rawParse = iOpt "raw"
-firstParse = iOpt "1"
-dontParse = iOpt "read"
+-- Default options
+
+defaultModuleFlags :: ModuleFlags
+defaultModuleFlags = ModuleFlags {
+ optName = Nothing,
+ optAbsName = Nothing,
+ optCncName = Nothing,
+ optResName = Nothing,
+ optPreprocessors = [],
+ optEncoding = ISO_8859_1,
+ optOptimizations = [OptStem,OptCSE,OptExpand,OptParametrize,OptValues],
+ optLibraryPath = [],
+ optStartCat = Nothing,
+ optSpeechLanguage = Nothing,
+ optLexer = Nothing,
+ optUnlexer = Nothing,
+ optBuildParser = True,
+ optWarnings = [],
+ optDump = []
+ }
+
+defaultFlags :: Flags
+defaultFlags = Flags {
+ optMode = ModeInteractive,
+ optStopAfterPhase = Compile,
+ optVerbosity = 1,
+ optShowCPUTime = False,
+ optEmitGFO = True,
+ optGFODir = ".",
+ optOutputFormats = [FmtGFCC],
+ optOutputFile = Nothing,
+ optOutputDir = Nothing,
+ optRecomp = RecompIfNewer,
+ optPrinter = [],
+ optProb = False,
+ optRetainResource = False,
+ optModuleFlags = defaultModuleFlags
+ }
+
+-- Option descriptions
+
+moduleOptDescr :: [OptDescr (Err ModuleOptions)]
+moduleOptDescr =
+ [
+ Option ['n'] ["name"] (ReqArg name "NAME")
+ (unlines ["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 [] ["abs"] (ReqArg absName "NAME")
+ ("Use NAME as the name of the abstract syntax module generated from "
+ ++ "a grammar in GF 1 format."),
+ Option [] ["cnc"] (ReqArg cncName "NAME")
+ ("Use NAME as the name of the concrete syntax module generated from "
+ ++ "a grammar in GF 1 format."),
+ Option [] ["res"] (ReqArg resName "NAME")
+ ("Use NAME as the name of the resource module generated from "
+ ++ "a grammar in GF 1 format."),
+ 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 [] ["coding"] (ReqArg coding "ENCODING")
+ ("Character encoding of the source grammar, ENCODING = "
+ ++ concat (intersperse " | " (map fst encodings)) ++ "."),
+ Option [] ["parser"] (onOff parser True) "Build parser (default on).",
+ Option [] ["startcat"] (ReqArg startcat "CAT") "Grammar start category.",
+ Option [] ["language"] (ReqArg language "LANG") "Set the speech language flag to LANG in the generated grammar.",
+ Option [] ["lexer"] (ReqArg lexer "LEXER") "Use lexer LEXER.",
+ Option [] ["unlexer"] (ReqArg unlexer "UNLEXER") "Use unlexer UNLEXER.",
+ Option [] ["optimize"] (ReqArg optimize "OPT")
+ "Select an optimization package. OPT = all | values | parametrize | none",
+ Option [] ["stem"] (onOff (toggleOptimize OptStem) True) "Perform stem-suffix analysis (default on).",
+ Option [] ["cse"] (onOff (toggleOptimize OptCSE) True) "Perform common sub-expression elimination (default on).",
+ dumpOption "rebuild" DumpRebuild,
+ dumpOption "extend" DumpExtend,
+ dumpOption "rename" DumpRename,
+ dumpOption "tc" DumpTypeCheck,
+ dumpOption "refresh" DumpRefresh,
+ dumpOption "opt" DumpOptimize,
+ dumpOption "canon" DumpCanon
+ ]
+ where
+ name x = set $ \o -> o { optName = Just x }
+ absName x = set $ \o -> o { optAbsName = Just x }
+ cncName x = set $ \o -> o { optCncName = Just x }
+ resName x = set $ \o -> o { optResName = Just x }
+ addLibDir x = set $ \o -> o { optLibraryPath = x:optLibraryPath o }
+ setLibPath x = set $ \o -> o { optLibraryPath = splitInModuleSearchPath x }
+ preproc x = set $ \o -> o { optPreprocessors = optPreprocessors o ++ [x] }
+ coding x = case lookup x encodings of
+ Just c -> set $ \o -> o { optEncoding = c }
+ Nothing -> fail $ "Unknown character encoding: " ++ x
+ parser x = set $ \o -> o { optBuildParser = x }
+ startcat x = set $ \o -> o { optStartCat = Just x }
+ language x = set $ \o -> o { optSpeechLanguage = Just x }
+ lexer x = set $ \o -> o { optLexer = Just x }
+ unlexer x = set $ \o -> o { optUnlexer = Just x }
+
+ optimize x = case lookup x optimizationPackages of
+ Just p -> set $ \o -> o { optOptimizations = p }
+ Nothing -> fail $ "Unknown optimization package: " ++ x
+
+ toggleOptimize x b = set $ \o -> o { optOptimizations = (if b then (x:) else delete x) (optOptimizations o) }
+
+ dumpOption s d = Option [] ["dump-"++s] (NoArg (set $ \o -> o { optDump = d:optDump o})) ("Dump output of the " ++ s ++ " phase.")
+
+ set = return . ModuleOptions
+
+optDescr :: [OptDescr (Err Options)]
+optDescr =
+ [
+ Option ['?','h'] ["help"] (NoArg (mode ModeHelp)) "Show help message.",
+ Option ['V'] ["version"] (NoArg (mode ModeVersion)) "Display GF version number.",
+ Option ['v'] ["verbose"] (OptArg verbosity "N") "Set verbosity (default 1). -v alone is the same as -v 3.",
+ Option ['q','s'] ["quiet"] (NoArg (verbosity (Just "0"))) "Quiet, same as -v 0.",
+ Option [] ["batch"] (NoArg (mode ModeCompiler)) "Run in batch compiler mode.",
+ Option [] ["interactive"] (NoArg (mode ModeInteractive)) "Run in interactive mode (default).",
+ 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 (default) .",
+ Option [] ["make"] (NoArg (phase Link)) "Build .gfcc file and other output files.",
+ 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 ['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 (recomp AlwaysRecomp))
+ "Always recompile from source.",
+ Option [] ["gfo","recomp-if-newer"] (NoArg (recomp RecompIfNewer))
+ "(default) Recompile from source if the source is newer than the .gfo file.",
+ Option [] ["gfo","no-recomp"] (NoArg (recomp NeverRecomp))
+ "Never recompile from source, if there is already .gfo file.",
+ Option [] ["strip"] (NoArg (printer PrinterStrip))
+ "Remove name qualifiers when pretty-printing.",
+ Option [] ["retain"] (NoArg (set $ \o -> o { optRetainResource = True })) "Retain opers.",
+ Option [] ["prob"] (NoArg (prob True)) "Read probabilities from '--# prob' pragmas."
+ ] ++ map (fmap (liftM moduleOptions)) moduleOptDescr
+ where phase x = set $ \o -> o { optStopAfterPhase = x }
+ mode x = set $ \o -> o { optMode = x }
+ verbosity mv = case mv of
+ Nothing -> set $ \o -> o { optVerbosity = 3 }
+ Just v -> case reads v of
+ [(i,"")] | i >= 0 -> set $ \o -> o { optVerbosity = i }
+ _ -> fail $ "Bad verbosity: " ++ show v
+ cpu x = set $ \o -> o { optShowCPUTime = x }
+ emitGFO x = set $ \o -> o { optEmitGFO = x }
+ gfoDir x = set $ \o -> o { optGFODir = x }
+ outFmt x = readOutputFormat x >>= \f ->
+ set $ \o -> o { optOutputFormats = optOutputFormats o ++ [f] }
+ outFile x = set $ \o -> o { optOutputFile = Just x }
+ outDir x = set $ \o -> o { optOutputDir = Just x }
+ recomp x = set $ \o -> o { optRecomp = x }
+ printer x = set $ \o -> o { optPrinter = x : optPrinter o }
+ prob x = set $ \o -> o { optProb = x }
+
+ set = return . Options
+
+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", FmtJavaScript),
+ ("haskell", FmtHaskell),
+ ("haskell_gadt", FmtHaskellGADT)]
+
+instance Show OutputFormat where
+ show = lookupShow outputFormats
+
+instance Read OutputFormat where
+ readsPrec = lookupReadsPrec outputFormats
+
+optimizationPackages :: [(String,[Optimization])]
+optimizationPackages =
+ [("all_subs", [OptStem,OptCSE,OptExpand,OptParametrize,OptValues]), -- deprecated
+ ("all", [OptStem,OptCSE,OptExpand,OptParametrize,OptValues]),
+ ("values", [OptStem,OptCSE,OptExpand,OptValues]),
+ ("parametrize", [OptStem,OptCSE,OptExpand,OptParametrize]),
+ ("none", [OptStem,OptCSE,OptExpand]),
+ ("noexpand", [OptStem,OptCSE])]
+
+encodings :: [(String,Encoding)]
+encodings =
+ [("utf8", UTF_8),
+ ("latin1", ISO_8859_1)]
+
+lookupShow :: Eq a => [(String,a)] -> a -> String
+lookupShow xs z = fromMaybe "lookupShow" $ lookup z [(y,x) | (x,y) <- xs]
+
+lookupReadsPrec :: [(String,a)] -> Int -> ReadS a
+lookupReadsPrec xs _ s = [(z,rest) | (x,rest) <- lex s, (y,z) <- xs, y == x]
+
+onOff :: Monad m => (Bool -> m a) -> Bool -> ArgDescr (m a)
+onOff f def = OptArg g "[on,off]"
+ where g ma = maybe (return def) readOnOff ma >>= f
+ 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
+
+-- FIXME: this is a copy of the function in GF.Devel.UseIO.
+splitInModuleSearchPath :: String -> [FilePath]
+splitInModuleSearchPath s = case break isPathSep s of
+ (f,_:cs) -> f : splitInModuleSearchPath cs
+ (f,_) -> [f]
+ where
+ isPathSep :: Char -> Bool
+ isPathSep c = c == ':' || c == ';'
+
+--
+-- * Convenience functions for checking options
+--
-newParser, newerParser, newCParser, newMParser :: Option
-newParser = iOpt "new"
-newerParser = iOpt "newer"
-newCParser = iOpt "cfg"
-newMParser = iOpt "mcfg"
-newFParser = iOpt "fcfg"
+beVerbose :: Options -> Bool
+beVerbose = flag ((>= 3) . optVerbosity)
-{-
-useParserMCFG, useParserMCFGviaCFG, useParserCFG, useParserCF :: Option
+beSilent :: Options -> Bool
+beSilent = flag ((<= 0) . optVerbosity)
-useParserMCFG = iOpt "mcfg"
-useParserMCFGviaCFG = iOpt "mcfg-via-cfg"
-useParserCFG = iOpt "cfg"
-useParserCF = iOpt "cf"
--}
+dump :: Options -> Dump -> Bool
+dump opts d = moduleFlag ((d `elem`) . optDump) opts
--- ** grammar formats
-
-showAbstr, showXML, showOld, showLatex, showFullForm,
- showEBNF, showCF, showWords, showOpts,
- isCompiled, isHaskell, noCompOpers, retainOpers,
- noCF, checkCirc, noCheckCirc, lexerByNeed, useUTF8id :: Option
-defaultGrOpts :: [Option]
-
-showAbstr = iOpt "abs"
-showXML = iOpt "xml"
-showOld = iOpt "old"
-showLatex = iOpt "latex"
-showFullForm = iOpt "fullform"
-showEBNF = iOpt "ebnf"
-showCF = iOpt "cf"
-showWords = iOpt "ws"
-showOpts = iOpt "opts"
--- showOptim = iOpt "opt"
-isCompiled = iOpt "gfc"
-isHaskell = iOpt "gfhs"
-noCompOpers = iOpt "nocomp"
-retainOpers = iOpt "retain"
-defaultGrOpts = []
-noCF = iOpt "nocf"
-checkCirc = iOpt "nocirc"
-noCheckCirc = iOpt "nocheckcirc"
-lexerByNeed = iOpt "cflexer"
-useUTF8id = iOpt "utf8id"
-elimSubs = iOpt "subs"
-
--- ** linearization
-
-allLin, firstLin, distinctLin, dontLin,
- showRecord, showStruct, xmlLin, latexLin,
- tableLin, useUTF8, showLang, withMetas :: Option
-defaultLinOpts :: [Option]
-
-allLin = iOpt "all"
-firstLin = iOpt "one"
-distinctLin = iOpt "nub"
-dontLin = iOpt "show"
-showRecord = iOpt "record"
-showStruct = iOpt "structured"
-xmlLin = showXML
-latexLin = showLatex
-tableLin = iOpt "table"
-defaultLinOpts = [firstLin]
-useUTF8 = iOpt "utf8"
-showLang = iOpt "lang"
-showDefs = iOpt "defs"
-withMetas = iOpt "metas"
-
--- ** other
-
-beVerbose, showInfo, beSilent, emitCode, getHelp,
- doMake, doBatch, notEmitCode, makeMulti, beShort,
- wholeGrammar, makeFudget, byLines, byWords, analMorpho,
- doTrace, noCPU, doCompute, optimizeCanon, optimizeValues,
- stripQualif, nostripQualif, showAll, fromSource :: Option
-
-beVerbose = iOpt "v"
-invertGrep = iOpt "v" --- same letter in unix
-showInfo = iOpt "i"
-beSilent = iOpt "s"
-emitCode = iOpt "o"
-getHelp = iOpt "help"
-doMake = iOpt "make"
-doBatch = iOpt "batch"
-notEmitCode = iOpt "noemit"
-makeMulti = iOpt "multi"
-beShort = iOpt "short"
-wholeGrammar = iOpt "w"
-makeFudget = iOpt "f"
-byLines = iOpt "lines"
-byWords = iOpt "words"
-analMorpho = iOpt "morpho"
-doTrace = iOpt "tr"
-noCPU = iOpt "nocpu"
-doCompute = iOpt "c"
-optimizeCanon = iOpt "opt"
-optimizeValues = iOpt "val"
-stripQualif = iOpt "strip"
-nostripQualif = iOpt "nostrip"
-showAll = iOpt "all"
-showFields = iOpt "fields"
-showMulti = iOpt "multi"
-fromSource = iOpt "src"
-makeConcrete = iOpt "examples"
-fromExamples = iOpt "ex"
-openEditor = iOpt "edit"
-getTrees = iOpt "trees"
-
--- ** mainly for stand-alone
-
-useUnicode, optCompute, optCheck, optParaphrase, forJava :: Option
-
-useUnicode = iOpt "unicode"
-optCompute = iOpt "compute"
-optCheck = iOpt "typecheck"
-optParaphrase = iOpt "paraphrase"
-forJava = iOpt "java"
-
--- ** for edit session
-
-allLangs, absView :: Option
-
-allLangs = iOpt "All"
-absView = iOpt "Abs"
-
--- ** options that take arguments
-
-useTokenizer, useUntokenizer, useParser, withFun,
- useLanguage, useResource, speechLanguage, useFont,
- grammarFormat, grammarPrinter, filterString, termCommand,
- transferFun, forForms, menuDisplay, sizeDisplay, typeDisplay,
- noDepTypes, extractGr, pathList, uniCoding :: String -> Option
--- | used on command line
-firstCat :: String -> Option
--- | used in grammar, to avoid clash w res word
-gStartCat :: String -> Option
-
-useTokenizer = aOpt "lexer"
-useUntokenizer = aOpt "unlexer"
-useParser = aOpt "parser"
--- useStrategy = aOpt "strategy" -- parsing strategy
-withFun = aOpt "fun"
-firstCat = aOpt "cat"
-gStartCat = aOpt "startcat"
-useLanguage = aOpt "lang"
-useResource = aOpt "res"
-speechLanguage = aOpt "language"
-useFont = aOpt "font"
-grammarFormat = aOpt "format"
-grammarPrinter = aOpt "printer"
-filterString = aOpt "filter"
-termCommand = aOpt "transform"
-transferFun = aOpt "transfer"
-forForms = aOpt "forms"
-menuDisplay = aOpt "menu"
-sizeDisplay = aOpt "size"
-typeDisplay = aOpt "types"
-noDepTypes = aOpt "nodeptypes"
-extractGr = aOpt "extract"
-pathList = aOpt "path"
-uniCoding = aOpt "coding"
-probFile = aOpt "probs"
-noparseFile = aOpt "noparse"
-usePreprocessor = aOpt "preproc"
-
--- peb 16/3-05:
-gfcConversion :: String -> Option
-gfcConversion = aOpt "conversion"
-
-useName, useAbsName, useCncName, useResName,
- useFile, useOptimizer :: String -> Option
-
-useName = aOpt "name"
-useAbsName = aOpt "abs"
-useCncName = aOpt "cnc"
-useResName = aOpt "res"
-useFile = aOpt "file"
-useOptimizer = aOpt "optimize"
-
-markLin :: String -> Option
-markOptXML, markOptJava, markOptStruct, markOptFocus :: String
-
-markLin = aOpt "mark"
-markOptXML = oArg "xml"
-markOptJava = oArg "java"
-markOptStruct = oArg "struct"
-markOptFocus = oArg "focus"
-
-
--- ** refinement order
-
-nextRefine :: String -> Option
-firstRefine, lastRefine :: String
-
-nextRefine = aOpt "nextrefine"
-firstRefine = oArg "first"
-lastRefine = oArg "last"
-
--- ** Boolean flags
-
-flagYes, flagNo :: String
-
-flagYes = oArg "yes"
-flagNo = oArg "no"
-
--- ** integer flags
-
-flagDepth, flagAlts, flagLength, flagNumber, flagRawtrees :: String -> Option
-
-flagDepth = aOpt "depth"
-flagAlts = aOpt "alts"
-flagLength = aOpt "length"
-flagNumber = aOpt "number"
-flagRawtrees = aOpt "rawtrees"
-
-caseYesNo :: Options -> OptFun -> Maybe Bool
-caseYesNo opts f = do
- v <- getOptVal opts f
- if v == flagYes then return True
- else if v == flagNo then return False
- else Nothing