1
0
forked from GitHub/gf-core

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.
This commit is contained in:
bjorn
2008-05-28 15:10:36 +00:00
parent 1bc74749aa
commit 3fd1f5652a
21 changed files with 1028 additions and 588 deletions

View File

@@ -2,12 +2,30 @@ module Main where
import GFC import GFC
import GFI import GFI
import GF.Data.ErrM
import GF.Infra.Option
import GF.Infra.UseIO
import Paths_gf
import Data.Version
import System.Environment (getArgs) import System.Environment (getArgs)
import System.Exit
import System.IO
main :: IO () main :: IO ()
main = do main =
args <- getArgs do args <- getArgs
case args of case parseOptions args of
"--batch":args -> mainGFC args Ok (opts,files) -> mainOpts opts files
_ -> mainGFI args Bad err -> do hPutStrLn stderr err
hPutStrLn stderr "You may want to try --help."
exitFailure
mainOpts :: Options -> [FilePath] -> IO ()
mainOpts opts files =
case flag optMode opts of
ModeVersion -> putStrLn $ "Grammatical Framework (GF) version " ++ showVersion version
ModeHelp -> putStrLn helpMessage
ModeInteractive -> mainGFI opts files
ModeCompiler -> dieIOE (mainGFC opts files)

View File

@@ -156,5 +156,5 @@ allCommands mgr = Map.fromAscList [
prGrammar opts = case valIdOpts "printer" "" opts of prGrammar opts = case valIdOpts "printer" "" opts of
"cats" -> unwords $ categories mgr "cats" -> unwords $ categories mgr
v -> prGFCC v gr v -> prGFCC (read v) gr

View File

@@ -1,4 +1,4 @@
module GF.Compile (batchCompile, compileToGFCC) where module GF.Compile (batchCompile, link, compileToGFCC) where
-- the main compiler passes -- the main compiler passes
import GF.Compile.GetGrammar import GF.Compile.GetGrammar
@@ -44,25 +44,34 @@ compileToGFCC :: Options -> [FilePath] -> IOE GFCC
compileToGFCC opts fs = compileToGFCC opts fs =
do gr <- batchCompile opts fs do gr <- batchCompile opts fs
let name = justModuleName (last fs) let name = justModuleName (last fs)
gc1 <- putPointE opts "linking ... " $ link opts name gr
let (abs,gc0) = mkCanon2gfcc opts name gr
in ioeIO $ checkGFCCio gc0
let opt = if oElem (iOpt "noopt") opts then id else optGFCC
par = if oElem (iOpt "noparse") opts then id else addParsers
return (par (opt gc1))
link :: Options -> String -> SourceGrammar -> IOE GFCC
link opts cnc gr =
do gc1 <- putPointE opts "linking ... " $
let (abs,gc0) = mkCanon2gfcc opts cnc gr
in ioeIO $ checkGFCCio gc0
return $ buildParser opts $ optimize opts gc1
optimize :: Options -> GFCC -> GFCC
optimize opts = cse . suf
where os = moduleFlag optOptimizations opts
cse = if OptCSE `elem` os then cseOptimize else id
suf = if OptStem `elem` os then suffixOptimize else id
buildParser :: Options -> GFCC -> GFCC
buildParser opts =
if moduleFlag optBuildParser opts then id else addParsers
batchCompile :: Options -> [FilePath] -> IOE SourceGrammar batchCompile :: Options -> [FilePath] -> IOE SourceGrammar
batchCompile opts files = do batchCompile opts files = do
(_,gr,_) <- foldM (compileModule defOpts) emptyCompileEnv files (_,gr,_) <- foldM (compileModule opts) emptyCompileEnv files
return gr return gr
where
defOpts = addOptions opts (options [emitCode])
-- to output an intermediate stage -- to output an intermediate stage
intermOut :: Options -> Option -> String -> IOE () intermOut :: Options -> Dump -> String -> IOE ()
intermOut opts opt s = if oElem opt opts then intermOut opts d s = if dump opts d then
ioeIO (putStrLn ("\n\n--#" +++ prOpt opt) >> putStrLn s) ioeIO (putStrLn ("\n\n--#" +++ show d) >> putStrLn s)
else return () else return ()
@@ -74,38 +83,31 @@ type CompileEnv = (Int,SourceGrammar,ModEnv)
-- As for path: if it is read from file, the file path is prepended to each name. -- As for path: if it is read from file, the file path is prepended to each name.
-- If from command line, it is used as it is. -- If from command line, it is used as it is.
compileModule :: Options -> CompileEnv -> FilePath -> IOE CompileEnv compileModule :: Options -- ^ Options from program command line and shell command.
-> CompileEnv -> FilePath -> IOE CompileEnv
compileModule opts1 env file = do compileModule opts1 env file = do
opts0 <- ioeIO $ getOptionsFromFile file opts0 <- getOptionsFromFile file
let useFileOpt = maybe False (const True) $ getOptVal opts0 pathList let opts = addOptions opts0 opts1
let useLineOpt = maybe False (const True) $ getOptVal opts1 pathList let fdir = dropFileName file
let opts = addOptions opts1 opts0 let ps0 = moduleFlag optLibraryPath opts
let fpath = dropFileName file ps2 <- ioeIO $ extendPathEnv $ fdir : ps0
ps0 <- ioeIO $ pathListOpts opts fpath let ps = ps2 ++ map (fdir </>) ps0
ioeIO $ putIfVerb opts $ "module search path:" +++ show ps ----
let ps1 = if (useFileOpt && not useLineOpt)
then (ps0 ++ map (combine fpath) ps0)
else ps0
ps <- ioeIO $ extendPathEnv ps1
let ioeIOIf = if oElem beVerbose opts then ioeIO else (const (return ()))
ioeIOIf $ putStrLn $ "module search path:" +++ show ps ----
let (_,sgr,rfs) = env let (_,sgr,rfs) = env
let file' = if useFileOpt then takeFileName file else file -- to find file itself files <- getAllFiles opts ps rfs file
files <- getAllFiles opts ps rfs file' ioeIO $ putIfVerb opts $ "files to read:" +++ show files ----
ioeIOIf $ putStrLn $ "files to read:" +++ show files ----
let names = map justModuleName files let names = map justModuleName files
ioeIOIf $ putStrLn $ "modules to include:" +++ show names ---- ioeIO $ putIfVerb opts $ "modules to include:" +++ show names ----
foldM (compileOne opts) (0,sgr,rfs) files foldM (compileOne opts) (0,sgr,rfs) files
compileOne :: Options -> CompileEnv -> FullPath -> IOE CompileEnv compileOne :: Options -> CompileEnv -> FullPath -> IOE CompileEnv
compileOne opts env@(_,srcgr,_) file = do compileOne opts env@(_,srcgr,_) file = do
let putp s = putPointE opts s let putp s = putPointE opts s
let putpp = putPointEsil opts let putpp = putPointEsil opts
let putpOpt v m act let putpOpt v m act
| oElem beVerbose opts = putp v act | beVerbose opts = putp v act
| oElem beSilent opts = putpp v act | beSilent opts = putpp v act
| otherwise = ioeIO (putStrFlush m) >> act | otherwise = ioeIO (putStrFlush m) >> act
let gf = takeExtensions file let gf = takeExtensions file
@@ -155,25 +157,25 @@ compileSourceModule opts env@(k,gr,_) mo@(i,mi) = do
mos = modules gr mos = modules gr
mo1 <- ioeErr $ rebuildModule mos mo mo1 <- ioeErr $ rebuildModule mos mo
intermOut opts (iOpt "show_rebuild") (prModule mo1) intermOut opts DumpRebuild (prModule mo1)
mo1b <- ioeErr $ extendModule mos mo1 mo1b <- ioeErr $ extendModule mos mo1
intermOut opts (iOpt "show_extend") (prModule mo1b) intermOut opts DumpExtend (prModule mo1b)
case mo1b of case mo1b of
(_,ModMod n) | not (isCompleteModule n) -> do (_,ModMod n) | not (isCompleteModule n) -> do
return (k,mo1b) -- refresh would fail, since not renamed return (k,mo1b) -- refresh would fail, since not renamed
_ -> do _ -> do
mo2:_ <- putpp " renaming " $ ioeErr $ renameModule mos mo1b mo2:_ <- putpp " renaming " $ ioeErr $ renameModule mos mo1b
intermOut opts (iOpt "show_rename") (prModule mo2) intermOut opts DumpRename (prModule mo2)
(mo3:_,warnings) <- putpp " type checking" $ ioeErr $ showCheckModule mos mo2 (mo3:_,warnings) <- putpp " type checking" $ ioeErr $ showCheckModule mos mo2
if null warnings then return () else putp warnings $ return () if null warnings then return () else putp warnings $ return ()
intermOut opts (iOpt "show_typecheck") (prModule mo3) intermOut opts DumpTypeCheck (prModule mo3)
(k',mo3r:_) <- putpp " refreshing " $ ioeErr $ refreshModule (k,mos) mo3 (k',mo3r:_) <- putpp " refreshing " $ ioeErr $ refreshModule (k,mos) mo3
intermOut opts (iOpt "show_refresh") (prModule mo3r) intermOut opts DumpRefresh (prModule mo3r)
let eenv = () --- emptyEEnv let eenv = () --- emptyEEnv
(mo4,eenv') <- (mo4,eenv') <-
@@ -197,9 +199,6 @@ generateModuleCode opts file minfo = do
-- auxiliaries -- auxiliaries
pathListOpts :: Options -> FileName -> IO [InitPath]
pathListOpts opts file = return $ maybe [file] splitInModuleSearchPath $ getOptVal opts pathList
reverseModules (MGrammar ms) = MGrammar $ reverse ms reverseModules (MGrammar ms) = MGrammar $ reverse ms
emptyCompileEnv :: CompileEnv emptyCompileEnv :: CompileEnv

View File

@@ -15,10 +15,11 @@
-- following advice of Josef Svenningsson -- following advice of Josef Svenningsson
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
module GF.Compile.BackOpt (shareModule, OptSpec, shareOpt, paramOpt, valOpt, allOpt) where module GF.Compile.BackOpt (shareModule, OptSpec) where
import GF.Grammar.Grammar import GF.Grammar.Grammar
import GF.Infra.Ident import GF.Infra.Ident
import GF.Infra.Option
import qualified GF.Grammar.Macros as C import qualified GF.Grammar.Macros as C
import GF.Grammar.PrGrammar (prt) import GF.Grammar.PrGrammar (prt)
import GF.Data.Operations import GF.Data.Operations
@@ -26,25 +27,7 @@ import Data.List
import qualified GF.Infra.Modules as M import qualified GF.Infra.Modules as M
import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Char8 as BS
type OptSpec = [Integer] --- type OptSpec = [Optimization]
doOptFactor :: OptSpec -> Bool
doOptFactor opt = elem 2 opt
doOptValues :: OptSpec -> Bool
doOptValues opt = elem 3 opt
shareOpt :: OptSpec
shareOpt = []
paramOpt :: OptSpec
paramOpt = [2]
valOpt :: OptSpec
valOpt = [3]
allOpt :: OptSpec
allOpt = [2,3]
shareModule :: OptSpec -> (Ident, SourceModInfo) -> (Ident, SourceModInfo) shareModule :: OptSpec -> (Ident, SourceModInfo) -> (Ident, SourceModInfo)
shareModule opt (i,m) = case m of shareModule opt (i,m) = case m of
@@ -59,31 +42,8 @@ shareInfo _ i = i
-- the function putting together optimizations -- the function putting together optimizations
shareOptim :: OptSpec -> Ident -> Term -> Term shareOptim :: OptSpec -> Ident -> Term -> Term
shareOptim opt c shareOptim opt c = (if OptValues `elem` opt then values else id)
| doOptFactor opt && doOptValues opt = values . factor c 0 . (if OptParametrize `elem` opt then factor c 0 else id)
| doOptFactor opt = share . factor c 0
| doOptValues opt = values
| otherwise = share
-- we need no counter to create new variable names, since variables are
-- local to tables (only true in GFC) ---
share :: Term -> Term
share t = case t of
T ty@(TComp _) cs -> shareT ty [(p, share v) | (p, v) <- cs]
_ -> C.composSafeOp share t
where
shareT ty = finalize ty . groupC . sortC
sortC :: [(Patt,Term)] -> [(Patt,Term)]
sortC = sortBy $ \a b -> compare (snd a) (snd b)
groupC :: [(Patt,Term)] -> [[(Patt,Term)]]
groupC = groupBy $ \a b -> snd a == snd b
finalize :: TInfo -> [[(Patt,Term)]] -> Term
finalize ty css = TSh ty [(map fst ps, t) | ps@((_,t):_) <- css]
-- do even more: factor parametric branches -- do even more: factor parametric branches

View File

@@ -39,15 +39,17 @@ import System.Cmd (system)
getSourceModule :: Options -> FilePath -> IOE SourceModule getSourceModule :: Options -> FilePath -> IOE SourceModule
getSourceModule opts file0 = do getSourceModule opts file0 = do
file <- case getOptVal opts usePreprocessor of file <- foldM runPreprocessor file0 (moduleFlag optPreprocessors opts)
Just p -> do
let tmp = "_gf_preproc.tmp"
cmd = p +++ file0 ++ ">" ++ tmp
ioeIO $ system cmd
-- ioeIO $ putStrLn $ "preproc" +++ cmd
return tmp
_ -> return file0
string <- readFileIOE file string <- readFileIOE file
let tokens = myLexer string let tokens = myLexer string
mo1 <- ioeErr $ pModDef tokens mo1 <- ioeErr $ pModDef tokens
ioeErr $ transModDef mo1 ioeErr $ transModDef mo1
-- FIXME: should use System.IO.openTempFile
runPreprocessor :: FilePath -> String -> IOE FilePath
runPreprocessor file0 p =
do let tmp = "_gf_preproc.tmp"
cmd = p +++ file0 ++ ">" ++ tmp
ioeIO $ system cmd
-- ioeIO $ putStrLn $ "preproc" +++ cmd
return tmp

View File

@@ -61,16 +61,15 @@ addParsers gfcc = gfcc { D.concretes = Map.map conv (D.concretes gfcc) }
canon2gfcc :: Options -> (Ident -> Ident -> C.Term) -> SourceGrammar -> D.GFCC canon2gfcc :: Options -> (Ident -> Ident -> C.Term) -> SourceGrammar -> D.GFCC
canon2gfcc opts pars cgr@(M.MGrammar ((a,M.ModMod abm):cms)) = canon2gfcc opts pars cgr@(M.MGrammar ((a,M.ModMod abm):cms)) =
(if (oElem (iOpt "show_canon") opts) then trace (prGrammar cgr) else id) $ (if dump opts DumpCanon then trace (prGrammar cgr) else id) $
D.GFCC an cns gflags abs cncs D.GFCC an cns gflags abs cncs
where where
-- abstract -- abstract
an = (i2i a) an = (i2i a)
cns = map (i2i . fst) cms cns = map (i2i . fst) cms
abs = D.Abstr aflags funs cats catfuns abs = D.Abstr aflags funs cats catfuns
gflags = Map.fromList [(mkCId fg,x) | Just x <- [getOptVal opts (aOpt fg)]] gflags = Map.empty
where fg = "firstlang" aflags = Map.fromList [(mkCId f,x) | (f,x) <- moduleOptionsGFO (M.flags abm)]
aflags = Map.fromList [(mkCId f,x) | Opt (f,[x]) <- M.flags abm]
mkDef pty = case pty of mkDef pty = case pty of
Yes t -> mkExp t Yes t -> mkExp t
_ -> CM.primNotion _ -> CM.primNotion
@@ -90,9 +89,9 @@ canon2gfcc opts pars cgr@(M.MGrammar ((a,M.ModMod abm):cms)) =
(lang,D.Concr flags lins opers lincats lindefs printnames params fcfg) (lang,D.Concr flags lins opers lincats lindefs printnames params fcfg)
where where
js = tree2list (M.jments mo) js = tree2list (M.jments mo)
flags = Map.fromList [(mkCId f,x) | Opt (f,[x]) <- M.flags mo] flags = Map.fromList [(mkCId f,x) | (f,x) <- moduleOptionsGFO (M.flags mo)]
opers = Map.fromAscList [] -- opers will be created as optimization opers = Map.fromAscList [] -- opers will be created as optimization
utf = if elem (Opt ("coding",["utf8"])) (M.flags mo) utf = if moduleFlag optEncoding (moduleOptions (M.flags mo)) == UTF_8
then D.convertStringsInTerm decodeUTF8 else id then D.convertStringsInTerm decodeUTF8 else id
lins = Map.fromAscList lins = Map.fromAscList
[(i2i f, utf (mkTerm tr)) | (f,CncFun _ (Yes tr) _) <- js] [(i2i f, utf (mkTerm tr)) | (f,CncFun _ (Yes tr) _) <- js]
@@ -227,14 +226,15 @@ reorder abs cg = M.MGrammar $
predefADefs ++ Look.allOrigInfos cg abs predefADefs ++ Look.allOrigInfos cg abs
predefADefs = predefADefs =
[(c, AbsCat (Yes []) Nope) | c <- [cFloat,cInt,cString]] [(c, AbsCat (Yes []) Nope) | c <- [cFloat,cInt,cString]]
aflags = nubFlags $ aflags =
concat [M.flags mo | (_,mo) <- M.allModMod cg, M.isModAbs mo] concatModuleOptions [M.flags mo | (_,mo) <- M.allModMod cg, M.isModAbs mo]
cncs = sortIds [(lang, concr lang) | lang <- M.allConcretes cg abs] cncs = sortIds [(lang, concr lang) | lang <- M.allConcretes cg abs]
concr la = (nubFlags flags, concr la = (flags,
sortIds (predefCDefs ++ jments)) where sortIds (predefCDefs ++ jments)) where
jments = Look.allOrigInfos cg la jments = Look.allOrigInfos cg la
flags = concat [M.flags mo | flags = concatModuleOptions
[M.flags mo |
(i,mo) <- mos, M.isModCnc mo, (i,mo) <- mos, M.isModCnc mo,
Just r <- [lookup i (M.allExtendSpecs cg la)]] Just r <- [lookup i (M.allExtendSpecs cg la)]]
@@ -242,7 +242,6 @@ reorder abs cg = M.MGrammar $
[(c, CncCat (Yes GM.defLinType) Nope Nope) | c <- [cInt,cFloat,cString]] [(c, CncCat (Yes GM.defLinType) Nope Nope) | c <- [cInt,cFloat,cString]]
sortIds = sortBy (\ (f,_) (g,_) -> compare f g) sortIds = sortBy (\ (f,_) (g,_) -> compare f g)
nubFlags = nubBy (\ (Opt (f,_)) (Opt (g,_)) -> f == g)
-- one grammar per language - needed for symtab generation -- one grammar per language - needed for symtab generation

View File

@@ -43,9 +43,6 @@ import Debug.Trace
prtIf :: (Print a) => Bool -> a -> a prtIf :: (Print a) => Bool -> a -> a
prtIf b t = if b then trace (" " ++ prt t) t else t prtIf b t = if b then trace (" " ++ prt t) t else t
-- experimental evaluation, option to import
oEval = iOpt "eval"
-- | partial evaluation of concrete syntax. AR 6\/2001 -- 16\/5\/2003 -- 5\/2\/2005. -- | partial evaluation of concrete syntax. AR 6\/2001 -- 16\/5\/2003 -- 5\/2\/2005.
type EEnv = () --- not used type EEnv = () --- not used
@@ -55,28 +52,21 @@ optimizeModule :: Options -> ([(Ident,SourceModInfo)],EEnv) ->
(Ident,SourceModInfo) -> Err ((Ident,SourceModInfo),EEnv) (Ident,SourceModInfo) -> Err ((Ident,SourceModInfo),EEnv)
optimizeModule opts mse@(ms,eenv) mo@(_,mi) = case mi of optimizeModule opts mse@(ms,eenv) mo@(_,mi) = case mi of
ModMod m0@(Module mt st fs me ops js) | ModMod m0@(Module mt st fs me ops js) |
st == MSComplete && isModRes m0 && not (oElem oEval oopts)-> do st == MSComplete && isModRes m0 -> do
(mo1,_) <- evalModule oopts mse mo (mo1,_) <- evalModule oopts mse mo
let let mo2 = shareModule optim mo1
mo2 = case optim of
"parametrize" -> shareModule paramOpt mo1 -- parametrization and sharing
"values" -> shareModule valOpt mo1 -- tables as courses-of-values
"share" -> shareModule shareOpt mo1 -- sharing of branches
"all" -> shareModule allOpt mo1 -- first parametrize then values
"none" -> mo1 -- no optimization
_ -> mo1 -- none; default for src
return (mo2,eenv) return (mo2,eenv)
_ -> evalModule oopts mse mo _ -> evalModule oopts mse mo
where where
oopts = addOptions opts (iOpts (flagsModule mo)) oopts = addOptions opts (moduleOptions (flagsModule mo))
optim = maybe "all" id $ getOptVal oopts useOptimizer optim = moduleFlag optOptimizations oopts
evalModule :: Options -> ([(Ident,SourceModInfo)],EEnv) -> (Ident,SourceModInfo) -> evalModule :: Options -> ([(Ident,SourceModInfo)],EEnv) -> (Ident,SourceModInfo) ->
Err ((Ident,SourceModInfo),EEnv) Err ((Ident,SourceModInfo),EEnv)
evalModule oopts (ms,eenv) mo@(name,mod) = case mod of evalModule oopts (ms,eenv) mo@(name,mod) = case mod of
ModMod m0@(Module mt st fs me ops js) | st == MSComplete -> case mt of ModMod m0@(Module mt st fs me ops js) | st == MSComplete -> case mt of
_ | isModRes m0 && not (oElem oEval oopts) -> do _ | isModRes m0 -> do
let deps = allOperDependencies name js let deps = allOperDependencies name js
ids <- topoSortOpers deps ids <- topoSortOpers deps
MGrammar (mod' : _) <- foldM evalOp gr ids MGrammar (mod' : _) <- foldM evalOp gr ids
@@ -112,17 +102,15 @@ evalResInfo oopts gr (c,info) = case info of
where where
comp = if optres then computeConcrete gr else computeConcreteRec gr comp = if optres then computeConcrete gr else computeConcreteRec gr
eIn cat = errIn ("Error optimizing" +++ cat +++ prt c +++ ":") eIn cat = errIn ("Error optimizing" +++ cat +++ prt c +++ ":")
optim = maybe "all" id $ getOptVal oopts useOptimizer optim = moduleFlag optOptimizations oopts
optres = case optim of optres = OptExpand `elem` optim
"noexpand" -> False
_ -> True
evalCncInfo :: evalCncInfo ::
Options -> SourceGrammar -> Ident -> Ident -> (Ident,Info) -> Err (Ident,Info) Options -> SourceGrammar -> Ident -> Ident -> (Ident,Info) -> Err (Ident,Info)
evalCncInfo opts gr cnc abs (c,info) = do evalCncInfo opts gr cnc abs (c,info) = do
seq (prtIf (oElem beVerbose opts) c) $ return () seq (prtIf (beVerbose opts) c) $ return ()
errIn ("optimizing" +++ prt c) $ case info of errIn ("optimizing" +++ prt c) $ case info of
@@ -143,7 +131,7 @@ evalCncInfo opts gr cnc abs (c,info) = do
CncFun (mt@(Just (_,ty@(cont,val)))) pde ppr -> CncFun (mt@(Just (_,ty@(cont,val)))) pde ppr ->
eIn ("linearization in type" +++ prt (mkProd (cont,val,[])) ++++ "of function") $ do eIn ("linearization in type" +++ prt (mkProd (cont,val,[])) ++++ "of function") $ do
pde' <- case pde of pde' <- case pde of
Yes de | notNewEval -> do Yes de -> do
liftM yes $ pEval ty de liftM yes $ pEval ty de
_ -> return pde _ -> return pde
@@ -154,7 +142,6 @@ evalCncInfo opts gr cnc abs (c,info) = do
where where
pEval = partEval opts gr pEval = partEval opts gr
eIn cat = errIn ("Error optimizing" +++ cat +++ prt c +++ ":") eIn cat = errIn ("Error optimizing" +++ cat +++ prt c +++ ":")
notNewEval = not (oElem oEval opts)
-- | the main function for compiling linearizations -- | the main function for compiling linearizations
partEval :: Options -> SourceGrammar -> (Context,Type) -> Term -> Err Term partEval :: Options -> SourceGrammar -> (Context,Type) -> Term -> Err Term

View File

@@ -19,8 +19,9 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
module GF.Compile.ReadFiles module GF.Compile.ReadFiles
( getAllFiles,ModName,ModEnv,getOptionsFromFile,importsOfModule, ( getAllFiles,ModName,ModEnv,importsOfModule,
gfoFile,gfFile,isGFO ) where gfoFile,gfFile,isGFO,
getOptionsFromFile) where
import GF.Infra.UseIO import GF.Infra.UseIO
import GF.Infra.Option import GF.Infra.Option
@@ -48,9 +49,7 @@ getAllFiles :: Options -> [InitPath] -> ModEnv -> FileName -> IOE [FullPath]
getAllFiles opts ps env file = do getAllFiles opts ps env file = do
-- read module headers from all files recursively -- read module headers from all files recursively
ds <- liftM reverse $ get [] [] (justModuleName file) ds <- liftM reverse $ get [] [] (justModuleName file)
if oElem beVerbose opts ioeIO $ putIfVerb opts $ "all modules:" +++ show [name | (name,_,_,_,_) <- ds]
then ioeIO $ putStrLn $ "all modules:" +++ show [name | (name,_,_,_,_) <- ds]
else return ()
return $ paths ds return $ paths ds
where where
-- construct list of paths to read -- construct list of paths to read
@@ -135,8 +134,8 @@ selectFormat opts mtenv mtgf mtgfo =
(_,_, Nothing) -> (CSRead,Nothing) -- source does not exist (_,_, Nothing) -> (CSRead,Nothing) -- source does not exist
_ -> (CSComp,Nothing) _ -> (CSComp,Nothing)
where where
fromComp = oElem isCompiled opts -- i -gfo fromComp = flag optRecomp opts == NeverRecomp
fromSrc = oElem fromSource opts fromSrc = flag optRecomp opts == AlwaysRecomp
-- internal module dep information -- internal module dep information
@@ -188,8 +187,9 @@ importsOfModule (MModule _ typ body) = modType typ (modBody body [])
-- | options can be passed to the compiler by comments in @--#@, in the main file -- | options can be passed to the compiler by comments in @--#@, in the main file
getOptionsFromFile :: FilePath -> IO Options getOptionsFromFile :: FilePath -> IOE Options
getOptionsFromFile file = do getOptionsFromFile file = do
s <- readFileIfStrict file s <- ioeIO $ readFileIfStrict file
let ls = filter (BS.isPrefixOf (BS.pack "--#")) $ BS.lines s let ls = filter (BS.isPrefixOf (BS.pack "--#")) $ BS.lines s
return $ fst $ getOptions "-" $ map (BS.unpack . BS.unwords . BS.words . BS.drop 3) ls fs = map (BS.unpack . BS.unwords . BS.words . BS.drop 3) ls
ioeErr $ liftM moduleOptions $ parseModuleOptions fs

View File

@@ -23,6 +23,7 @@ import GF.Grammar.Macros
import GF.Infra.Ident import GF.Infra.Ident
import GF.Infra.Modules import GF.Infra.Modules
import GF.Infra.Option
import GF.Data.Operations import GF.Data.Operations
import Data.List (nub) import Data.List (nub)
@@ -76,7 +77,7 @@ rebuildModule ms mo@(i,mi) = do
++ [oSimple i | i <- map snd insts] ---- ++ [oSimple i | i <- map snd insts] ----
--- check if me is incomplete --- check if me is incomplete
let fs1 = fs_ ++ fs -- new flags have priority let fs1 = addModuleOptions fs fs_ -- new flags have priority
let js0 = [ci | ci@(c,_) <- tree2list js, isInherited incl c] let js0 = [ci | ci@(c,_) <- tree2list js, isInherited incl c]
let js1 = buildTree (tree2list js_ ++ js0) let js1 = buildTree (tree2list js_ ++ js0)
return $ ModMod $ Module mt0 stat' fs1 me ops1 js1 return $ ModMod $ Module mt0 stat' fs1 me ops1 js1

View File

@@ -13,7 +13,10 @@ import qualified Data.Map as Map
-- suffix analysis followed by common subexpression elimination -- suffix analysis followed by common subexpression elimination
optGFCC :: GFCC -> GFCC optGFCC :: GFCC -> GFCC
optGFCC gfcc = gfcc { optGFCC = cseOptimize . suffixOptimize
suffixOptimize :: GFCC -> GFCC
suffixOptimize gfcc = gfcc {
concretes = Map.map opt (concretes gfcc) concretes = Map.map opt (concretes gfcc)
} }
where where
@@ -23,6 +26,11 @@ optGFCC gfcc = gfcc {
printnames = Map.map optTerm (printnames cnc) printnames = Map.map optTerm (printnames cnc)
} }
cseOptimize :: GFCC -> GFCC
cseOptimize gfcc = gfcc {
concretes = Map.map subex (concretes gfcc)
}
-- analyse word form lists into prefix + suffixes -- analyse word form lists into prefix + suffixes
-- suffix sets can later be shared by subex elim -- suffix sets can later be shared by subex elim

View File

@@ -5,16 +5,17 @@ import GF.GFCC.Raw.ConvertGFCC (fromGFCC)
import GF.GFCC.Raw.PrintGFCCRaw (printTree) import GF.GFCC.Raw.PrintGFCCRaw (printTree)
import GF.GFCC.GFCCtoHaskell import GF.GFCC.GFCCtoHaskell
import GF.GFCC.GFCCtoJS import GF.GFCC.GFCCtoJS
import GF.Infra.Option
import GF.Text.UTF8 import GF.Text.UTF8
-- top-level access to code generation -- top-level access to code generation
prGFCC :: String -> GFCC -> String prGFCC :: OutputFormat -> GFCC -> String
prGFCC printer gr = case printer of prGFCC fmt gr = case fmt of
"haskell" -> grammar2haskell gr FmtGFCC -> printGFCC gr
"haskell_gadt" -> grammar2haskellGADT gr FmtJavaScript -> gfcc2js gr
"js" -> gfcc2js gr FmtHaskell -> grammar2haskell gr
_ -> printGFCC gr FmtHaskellGADT -> grammar2haskellGADT gr
printGFCC :: GFCC -> String printGFCC :: GFCC -> String
printGFCC = encodeUTF8 . printTree . fromGFCC printGFCC = encodeUTF8 . printTree . fromGFCC

View File

@@ -5,7 +5,8 @@ module GF.Grammar.API (
prTerm, prTerm,
checkTerm, checkTerm,
computeTerm, computeTerm,
showTerm showTerm,
TermPrintStyle(..)
) where ) where
import GF.Source.ParGF import GF.Source.ParGF
@@ -52,9 +53,15 @@ checkTermAny gr m t = do
computeTerm :: Grammar -> Term -> Err Term computeTerm :: Grammar -> Term -> Err Term
computeTerm = computeConcrete computeTerm = computeConcrete
showTerm :: Options -> Term -> String showTerm :: TermPrintStyle -> Term -> String
showTerm opts t showTerm style t =
| oElem (iOpt "table") opts = unlines [p +++ s | (p,s) <- prTermTabular t] case style of
| oElem (iOpt "all") opts = unlines [ s | (p,s) <- prTermTabular t] TermPrintTable -> unlines [p +++ s | (p,s) <- prTermTabular t]
| oElem (iOpt "unqual") opts = prt_ t TermPrintAll -> unlines [ s | (p,s) <- prTermTabular t]
| otherwise = prt t TermPrintUnqual -> prt_ t
TermPrintDefault -> prt t
data TermPrintStyle = TermPrintTable | TermPrintAll | TermPrintUnqual | TermPrintDefault
deriving (Show,Eq)

View File

@@ -233,7 +233,7 @@ prExp e = case e of
-- | option @-strip@ strips qualifications -- | option @-strip@ strips qualifications
prTermOpt :: Options -> Term -> String prTermOpt :: Options -> Term -> String
prTermOpt opts = if oElem nostripQualif opts then prt else prExp prTermOpt opts = if PrinterStrip `elem` flag optPrinter opts then prt else prExp
-- | to get rid of brackets in the editor -- | to get rid of brackets in the editor
prRefinement :: Term -> String prRefinement :: Term -> String

381
src-3.0/GF/Infra/GetOpt.hs Normal file
View File

@@ -0,0 +1,381 @@
-- This is a version of System.Console.GetOpt which has been hacked to
-- support long options with a single dash. Since we don't want the annoying
-- clash with short options that start with the same character as a long
-- one, we don't allow short options to be given together (e.g. -zxf),
-- nor do we allow options to be given as any unique prefix.
-----------------------------------------------------------------------------
-- |
-- Module : System.Console.GetOpt
-- Copyright : (c) Sven Panne 2002-2005
-- License : BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer : libraries@haskell.org
-- Stability : experimental
-- Portability : portable
--
-- This library provides facilities for parsing the command-line options
-- in a standalone program. It is essentially a Haskell port of the GNU
-- @getopt@ library.
--
-----------------------------------------------------------------------------
{-
Sven Panne <Sven.Panne@informatik.uni-muenchen.de> Oct. 1996 (small
changes Dec. 1997)
Two rather obscure features are missing: The Bash 2.0 non-option hack
(if you don't already know it, you probably don't want to hear about
it...) and the recognition of long options with a single dash
(e.g. '-help' is recognised as '--help', as long as there is no short
option 'h').
Other differences between GNU's getopt and this implementation:
* To enforce a coherent description of options and arguments, there
are explanation fields in the option/argument descriptor.
* Error messages are now more informative, but no longer POSIX
compliant... :-(
And a final Haskell advertisement: The GNU C implementation uses well
over 1100 lines, we need only 195 here, including a 46 line example!
:-)
-}
--module System.Console.GetOpt (
module GF.Infra.GetOpt (
-- * GetOpt
getOpt, getOpt',
usageInfo,
ArgOrder(..),
OptDescr(..),
ArgDescr(..),
-- * Examples
-- |To hopefully illuminate the role of the different data structures,
-- here are the command-line options for a (very simple) compiler,
-- done in two different ways.
-- The difference arises because the type of 'getOpt' is
-- parameterized by the type of values derived from flags.
-- ** Interpreting flags as concrete values
-- $example1
-- ** Interpreting flags as transformations of an options record
-- $example2
) where
import Prelude -- necessary to get dependencies right
import Data.List ( isPrefixOf, find )
-- |What to do with options following non-options
data ArgOrder a
= RequireOrder -- ^ no option processing after first non-option
| Permute -- ^ freely intersperse options and non-options
| ReturnInOrder (String -> a) -- ^ wrap non-options into options
{-|
Each 'OptDescr' describes a single option.
The arguments to 'Option' are:
* list of short option characters
* list of long option strings (without \"--\")
* argument descriptor
* explanation of option for user
-}
data OptDescr a = -- description of a single options:
Option [Char] -- list of short option characters
[String] -- list of long option strings (without "--")
(ArgDescr a) -- argument descriptor
String -- explanation of option for user
-- |Describes whether an option takes an argument or not, and if so
-- how the argument is injected into a value of type @a@.
data ArgDescr a
= NoArg a -- ^ no argument expected
| ReqArg (String -> a) String -- ^ option requires argument
| OptArg (Maybe String -> a) String -- ^ optional argument
data OptKind a -- kind of cmd line arg (internal use only):
= Opt a -- an option
| UnreqOpt String -- an un-recognized option
| NonOpt String -- a non-option
| EndOfOpts -- end-of-options marker (i.e. "--")
| OptErr String -- something went wrong...
-- | Return a string describing the usage of a command, derived from
-- the header (first argument) and the options described by the
-- second argument.
usageInfo :: String -- header
-> [OptDescr a] -- option descriptors
-> String -- nicely formatted decription of options
usageInfo header optDescr = unlines (header:table)
where (ss,ls,ds) = (unzip3 . concatMap fmtOpt) optDescr
table = zipWith3 paste (sameLen ss) (sameLen ls) ds
paste x y z = " " ++ x ++ " " ++ y ++ " " ++ z
sameLen xs = flushLeft ((maximum . map length) xs) xs
flushLeft n xs = [ take n (x ++ repeat ' ') | x <- xs ]
fmtOpt :: OptDescr a -> [(String,String,String)]
fmtOpt (Option sos los ad descr) =
case lines descr of
[] -> [(sosFmt,losFmt,"")]
(d:ds) -> (sosFmt,losFmt,d) : [ ("","",d') | d' <- ds ]
where sepBy _ [] = ""
sepBy _ [x] = x
sepBy ch (x:xs) = x ++ ch:' ':sepBy ch xs
sosFmt = sepBy ',' (map (fmtShort ad) sos)
losFmt = sepBy ',' (map (fmtLong ad) los)
fmtShort :: ArgDescr a -> Char -> String
fmtShort (NoArg _ ) so = "-" ++ [so]
fmtShort (ReqArg _ ad) so = "-" ++ [so] ++ " " ++ ad
fmtShort (OptArg _ ad) so = "-" ++ [so] ++ "[" ++ ad ++ "]"
fmtLong :: ArgDescr a -> String -> String
fmtLong (NoArg _ ) lo = "--" ++ lo
fmtLong (ReqArg _ ad) lo = "--" ++ lo ++ "=" ++ ad
fmtLong (OptArg _ ad) lo = "--" ++ lo ++ "[=" ++ ad ++ "]"
{-|
Process the command-line, and return the list of values that matched
(and those that didn\'t). The arguments are:
* The order requirements (see 'ArgOrder')
* The option descriptions (see 'OptDescr')
* The actual command line arguments (presumably got from
'System.Environment.getArgs').
'getOpt' returns a triple consisting of the option arguments, a list
of non-options, and a list of error messages.
-}
getOpt :: ArgOrder a -- non-option handling
-> [OptDescr a] -- option descriptors
-> [String] -- the command-line arguments
-> ([a],[String],[String]) -- (options,non-options,error messages)
getOpt ordering optDescr args = (os,xs,es ++ map errUnrec us)
where (os,xs,us,es) = getOpt' ordering optDescr args
{-|
This is almost the same as 'getOpt', but returns a quadruple
consisting of the option arguments, a list of non-options, a list of
unrecognized options, and a list of error messages.
-}
getOpt' :: ArgOrder a -- non-option handling
-> [OptDescr a] -- option descriptors
-> [String] -- the command-line arguments
-> ([a],[String], [String] ,[String]) -- (options,non-options,unrecognized,error messages)
getOpt' _ _ [] = ([],[],[],[])
getOpt' ordering optDescr (arg:args) = procNextOpt opt ordering
where procNextOpt (Opt o) _ = (o:os,xs,us,es)
procNextOpt (UnreqOpt u) _ = (os,xs,u:us,es)
procNextOpt (NonOpt x) RequireOrder = ([],x:rest,[],[])
procNextOpt (NonOpt x) Permute = (os,x:xs,us,es)
procNextOpt (NonOpt x) (ReturnInOrder f) = (f x :os, xs,us,es)
procNextOpt EndOfOpts RequireOrder = ([],rest,[],[])
procNextOpt EndOfOpts Permute = ([],rest,[],[])
procNextOpt EndOfOpts (ReturnInOrder f) = (map f rest,[],[],[])
procNextOpt (OptErr e) _ = (os,xs,us,e:es)
(opt,rest) = getNext arg args optDescr
(os,xs,us,es) = getOpt' ordering optDescr rest
-- take a look at the next cmd line arg and decide what to do with it
getNext :: String -> [String] -> [OptDescr a] -> (OptKind a,[String])
getNext ('-':'-':[]) rest _ = (EndOfOpts,rest)
getNext ('-':'-':xs) rest optDescr = longOpt xs rest optDescr
getNext ('-' :xs) rest optDescr = longOpt xs rest optDescr
getNext a rest _ = (NonOpt a,rest)
-- handle long option
longOpt :: String -> [String] -> [OptDescr a] -> (OptKind a,[String])
longOpt ls rs optDescr = long ads arg rs
where (opt,arg) = break (=='=') ls
options = [ o | o@(Option ss xs _ _) <- optDescr
, opt `elem` map (:[]) ss || opt `elem` xs ]
ads = [ ad | Option _ _ ad _ <- options ]
optStr = ("--"++opt)
long (_:_:_) _ rest = (errAmbig options optStr,rest)
long [NoArg a ] [] rest = (Opt a,rest)
long [NoArg _ ] ('=':_) rest = (errNoArg optStr,rest)
long [ReqArg _ d] [] [] = (errReq d optStr,[])
long [ReqArg f _] [] (r:rest) = (Opt (f r),rest)
long [ReqArg f _] ('=':xs) rest = (Opt (f xs),rest)
long [OptArg f _] [] rest = (Opt (f Nothing),rest)
long [OptArg f _] ('=':xs) rest = (Opt (f (Just xs)),rest)
long _ _ rest = (UnreqOpt ("--"++ls),rest)
-- miscellaneous error formatting
errAmbig :: [OptDescr a] -> String -> OptKind a
errAmbig ods optStr = OptErr (usageInfo header ods)
where header = "option `" ++ optStr ++ "' is ambiguous; could be one of:"
errReq :: String -> String -> OptKind a
errReq d optStr = OptErr ("option `" ++ optStr ++ "' requires an argument " ++ d ++ "\n")
errUnrec :: String -> String
errUnrec optStr = "unrecognized option `" ++ optStr ++ "'\n"
errNoArg :: String -> OptKind a
errNoArg optStr = OptErr ("option `" ++ optStr ++ "' doesn't allow an argument\n")
{-
-----------------------------------------------------------------------------------------
-- and here a small and hopefully enlightening example:
data Flag = Verbose | Version | Name String | Output String | Arg String deriving Show
options :: [OptDescr Flag]
options =
[Option ['v'] ["verbose"] (NoArg Verbose) "verbosely list files",
Option ['V','?'] ["version","release"] (NoArg Version) "show version info",
Option ['o'] ["output"] (OptArg out "FILE") "use FILE for dump",
Option ['n'] ["name"] (ReqArg Name "USER") "only dump USER's files"]
out :: Maybe String -> Flag
out Nothing = Output "stdout"
out (Just o) = Output o
test :: ArgOrder Flag -> [String] -> String
test order cmdline = case getOpt order options cmdline of
(o,n,[] ) -> "options=" ++ show o ++ " args=" ++ show n ++ "\n"
(_,_,errs) -> concat errs ++ usageInfo header options
where header = "Usage: foobar [OPTION...] files..."
-- example runs:
-- putStr (test RequireOrder ["foo","-v"])
-- ==> options=[] args=["foo", "-v"]
-- putStr (test Permute ["foo","-v"])
-- ==> options=[Verbose] args=["foo"]
-- putStr (test (ReturnInOrder Arg) ["foo","-v"])
-- ==> options=[Arg "foo", Verbose] args=[]
-- putStr (test Permute ["foo","--","-v"])
-- ==> options=[] args=["foo", "-v"]
-- putStr (test Permute ["-?o","--name","bar","--na=baz"])
-- ==> options=[Version, Output "stdout", Name "bar", Name "baz"] args=[]
-- putStr (test Permute ["--ver","foo"])
-- ==> option `--ver' is ambiguous; could be one of:
-- -v --verbose verbosely list files
-- -V, -? --version, --release show version info
-- Usage: foobar [OPTION...] files...
-- -v --verbose verbosely list files
-- -V, -? --version, --release show version info
-- -o[FILE] --output[=FILE] use FILE for dump
-- -n USER --name=USER only dump USER's files
-----------------------------------------------------------------------------------------
-}
{- $example1
A simple choice for the type associated with flags is to define a type
@Flag@ as an algebraic type representing the possible flags and their
arguments:
> module Opts1 where
>
> import System.Console.GetOpt
> import Data.Maybe ( fromMaybe )
>
> data Flag
> = Verbose | Version
> | Input String | Output String | LibDir String
> deriving Show
>
> options :: [OptDescr Flag]
> options =
> [ Option ['v'] ["verbose"] (NoArg Verbose) "chatty output on stderr"
> , Option ['V','?'] ["version"] (NoArg Version) "show version number"
> , Option ['o'] ["output"] (OptArg outp "FILE") "output FILE"
> , Option ['c'] [] (OptArg inp "FILE") "input FILE"
> , Option ['L'] ["libdir"] (ReqArg LibDir "DIR") "library directory"
> ]
>
> inp,outp :: Maybe String -> Flag
> outp = Output . fromMaybe "stdout"
> inp = Input . fromMaybe "stdin"
>
> compilerOpts :: [String] -> IO ([Flag], [String])
> compilerOpts argv =
> case getOpt Permute options argv of
> (o,n,[] ) -> return (o,n)
> (_,_,errs) -> ioError (userError (concat errs ++ usageInfo header options))
> where header = "Usage: ic [OPTION...] files..."
Then the rest of the program will use the constructed list of flags
to determine it\'s behaviour.
-}
{- $example2
A different approach is to group the option values in a record of type
@Options@, and have each flag yield a function of type
@Options -> Options@ transforming this record.
> module Opts2 where
>
> import System.Console.GetOpt
> import Data.Maybe ( fromMaybe )
>
> data Options = Options
> { optVerbose :: Bool
> , optShowVersion :: Bool
> , optOutput :: Maybe FilePath
> , optInput :: Maybe FilePath
> , optLibDirs :: [FilePath]
> } deriving Show
>
> defaultOptions = Options
> { optVerbose = False
> , optShowVersion = False
> , optOutput = Nothing
> , optInput = Nothing
> , optLibDirs = []
> }
>
> options :: [OptDescr (Options -> Options)]
> options =
> [ Option ['v'] ["verbose"]
> (NoArg (\ opts -> opts { optVerbose = True }))
> "chatty output on stderr"
> , Option ['V','?'] ["version"]
> (NoArg (\ opts -> opts { optShowVersion = True }))
> "show version number"
> , Option ['o'] ["output"]
> (OptArg ((\ f opts -> opts { optOutput = Just f }) . fromMaybe "output")
> "FILE")
> "output FILE"
> , Option ['c'] []
> (OptArg ((\ f opts -> opts { optInput = Just f }) . fromMaybe "input")
> "FILE")
> "input FILE"
> , Option ['L'] ["libdir"]
> (ReqArg (\ d opts -> opts { optLibDirs = optLibDirs opts ++ [d] }) "DIR")
> "library directory"
> ]
>
> compilerOpts :: [String] -> IO (Options, [String])
> compilerOpts argv =
> case getOpt Permute options argv of
> (o,n,[] ) -> return (foldl (flip id) defaultOptions o, n)
> (_,_,errs) -> ioError (userError (concat errs ++ usageInfo header options))
> where header = "Usage: ic [OPTION...] files..."
Similarly, each flag could yield a monadic function transforming a record,
of type @Options -> IO Options@ (or any other monad), allowing option
processing to perform actions of the chosen monad, e.g. printing help or
version messages, checking that file arguments exist, etc.
-}

View File

@@ -65,7 +65,7 @@ data ModInfo i a =
data Module i a = Module { data Module i a = Module {
mtype :: ModuleType i , mtype :: ModuleType i ,
mstatus :: ModuleStatus , mstatus :: ModuleStatus ,
flags :: [Option] , flags :: ModuleOptions,
extend :: [(i,MInclude i)], extend :: [(i,MInclude i)],
opens :: [OpenSpec i] , opens :: [OpenSpec i] ,
jments :: BinTree i a jments :: BinTree i a
@@ -126,16 +126,16 @@ addOpenQualif :: i -> i -> Module i t -> Module i t
addOpenQualif i j (Module mt ms fs me ops js) = addOpenQualif i j (Module mt ms fs me ops js) =
Module mt ms fs me (oQualif i j : ops) js Module mt ms fs me (oQualif i j : ops) js
addFlag :: Option -> Module i t -> Module i t addFlag :: ModuleOptions -> Module i t -> Module i t
addFlag f mo = mo {flags = f : flags mo} addFlag f mo = mo {flags = addModuleOptions (flags mo) f}
flagsModule :: (i,ModInfo i a) -> [Option] flagsModule :: (i,ModInfo i a) -> ModuleOptions
flagsModule (_,mi) = case mi of flagsModule (_,mi) = case mi of
ModMod m -> flags m ModMod m -> flags m
_ -> [] _ -> noModuleOptions
allFlags :: MGrammar i a -> [Option] allFlags :: MGrammar i a -> ModuleOptions
allFlags gr = concat $ map flags $ [m | (_, ModMod m) <- modules gr] allFlags gr = concatModuleOptions $ map flags $ [m | (_, ModMod m) <- modules gr]
mapModules :: (Module i a -> Module i a) mapModules :: (Module i a -> Module i a)
-> MGrammar i a -> MGrammar i a -> MGrammar i a -> MGrammar i a
@@ -267,7 +267,7 @@ emptyModInfo :: ModInfo i a
emptyModInfo = ModMod emptyModule emptyModInfo = ModMod emptyModule
emptyModule :: Module i a emptyModule :: Module i a
emptyModule = Module MTResource MSComplete [] [] [] emptyBinTree emptyModule = Module MTResource MSComplete noModuleOptions [] [] emptyBinTree
-- | we store the module type with the identifier -- | we store the module type with the identifier
data IdentM i = IdentM { data IdentM i = IdentM {

View File

@@ -1,375 +1,464 @@
---------------------------------------------------------------------- module GF.Infra.Option
-- | (
-- Module : Option -- * Option types
-- Maintainer : AR Options, ModuleOptions,
-- Stability : (stable) Flags(..), ModuleFlags(..),
-- Portability : (portable) Mode(..), Phase(..), Encoding(..), OutputFormat(..), Optimization(..),
-- Dump(..), Printer(..), Recomp(..),
-- > CVS $Date: 2005/11/14 16:03:41 $ -- * Option parsing
-- > CVS $Author: aarne $ parseOptions, parseModuleOptions,
-- > CVS $Revision: 1.34 $ -- * Option pretty-printing
-- moduleOptionsGFO,
-- Options and flags used in GF shell commands and files. -- * Option manipulation
-- addOptions, concatOptions, noOptions,
-- The types 'Option' and 'Options' should be kept abstract, but: moduleOptions,
-- addModuleOptions, concatModuleOptions, noModuleOptions,
-- - The constructor 'Opt' is used in "ShellCommands" and "GrammarToSource" helpMessage,
-- -- * Checking options
-- - The constructor 'Opts' us udes in "API", "Shell" and "ShellCommands" flag, moduleFlag,
----------------------------------------------------------------------------- -- * Convenience methods for checking options
beVerbose, beSilent,
dump
) where
module GF.Infra.Option 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 Data.List (partition) import GF.Data.ErrM
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)
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 :: Options
noOptions = Opts [] noOptions = Options id
-- | simple option -o addOptions :: Options -- ^ Existing options.
iOpt :: String -> Option -> Options -- ^ Options to add (these take preference).
iOpt o = Opt (o,[]) -> Options
addOptions (Options o1) (Options o2) = Options (o2 . o1)
-- | 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
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
concatOptions :: [Options] -> Options concatOptions :: [Options] -> Options
concatOptions = foldr addOptions noOptions concatOptions = foldr addOptions noOptions
removeOption :: Option -> Options -> Options moduleOptions :: ModuleOptions -> Options
removeOption o (Opts os) = iOpts (filter (/=o) os) moduleOptions (ModuleOptions f) = Options (\o -> o { optModuleFlags = f (optModuleFlags o) })
removeOptions :: Options -> Options -> Options addModuleOptions :: ModuleOptions -- ^ Existing options.
removeOptions (Opts os) os0 = foldr removeOption os0 os -> ModuleOptions -- ^ Options to add (these take preference).
-> ModuleOptions
addModuleOptions (ModuleOptions o1) (ModuleOptions o2) = ModuleOptions (o2 . o1)
options :: [Option] -> Options concatModuleOptions :: [ModuleOptions] -> ModuleOptions
options = foldr addOption noOptions concatModuleOptions = foldr addModuleOptions noModuleOptions
unionOptions :: Options -> Options -> Options noModuleOptions :: ModuleOptions
unionOptions (Opts os) (Opts os') = Opts (os ++ os') noModuleOptions = ModuleOptions id
-- * parsing options, with prefix pre (e.g. \"-\") flag :: (Flags -> a) -> Options -> a
flag f (Options o) = f (o defaultFlags)
getOptions :: String -> [String] -> (Options, [String]) moduleFlag :: (ModuleFlags -> a) -> Options -> a
getOptions pre inp = let moduleFlag f = flag (f . optModuleFlags)
(os,rest) = span (isOption pre) inp -- options before args
in
(Opts (map (pOption pre) os), rest)
pOption :: String -> String -> Option
pOption pre s = case span (/= '=') (drop (length pre) s) of
(f,_:a) -> aOpt f a
(o,[]) -> iOpt o
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
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"
newParser, newerParser, newCParser, newMParser :: Option
newParser = iOpt "new"
newerParser = iOpt "newer"
newCParser = iOpt "cfg"
newMParser = iOpt "mcfg"
newFParser = iOpt "fcfg"
{- {-
useParserMCFG, useParserMCFGviaCFG, useParserCFG, useParserCF :: Option
useParserMCFG = iOpt "mcfg" parseModuleFlags :: Options -> [(String,Maybe String)] -> Err ModuleOptions
useParserMCFGviaCFG = iOpt "mcfg-via-cfg" parseModuleFlags opts flags =
useParserCFG = iOpt "cfg" mapM (uncurry (findFlag moduleOptDescr)) flags >>= foldM (flip ($)) (optModuleOptions opts)
useParserCF = iOpt "cf"
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)
-} -}
-- ** grammar formats -- Default options
showAbstr, showXML, showOld, showLatex, showFullForm, defaultModuleFlags :: ModuleFlags
showEBNF, showCF, showWords, showOpts, defaultModuleFlags = ModuleFlags {
isCompiled, isHaskell, noCompOpers, retainOpers, optName = Nothing,
noCF, checkCirc, noCheckCirc, lexerByNeed, useUTF8id :: Option optAbsName = Nothing,
defaultGrOpts :: [Option] 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 = []
}
showAbstr = iOpt "abs" defaultFlags :: Flags
showXML = iOpt "xml" defaultFlags = Flags {
showOld = iOpt "old" optMode = ModeInteractive,
showLatex = iOpt "latex" optStopAfterPhase = Compile,
showFullForm = iOpt "fullform" optVerbosity = 1,
showEBNF = iOpt "ebnf" optShowCPUTime = False,
showCF = iOpt "cf" optEmitGFO = True,
showWords = iOpt "ws" optGFODir = ".",
showOpts = iOpt "opts" optOutputFormats = [FmtGFCC],
-- showOptim = iOpt "opt" optOutputFile = Nothing,
isCompiled = iOpt "gfc" optOutputDir = Nothing,
isHaskell = iOpt "gfhs" optRecomp = RecompIfNewer,
noCompOpers = iOpt "nocomp" optPrinter = [],
retainOpers = iOpt "retain" optProb = False,
defaultGrOpts = [] optRetainResource = False,
noCF = iOpt "nocf" optModuleFlags = defaultModuleFlags
checkCirc = iOpt "nocirc" }
noCheckCirc = iOpt "nocheckcirc"
lexerByNeed = iOpt "cflexer"
useUTF8id = iOpt "utf8id"
elimSubs = iOpt "subs"
-- ** linearization -- Option descriptions
allLin, firstLin, distinctLin, dontLin, moduleOptDescr :: [OptDescr (Err ModuleOptions)]
showRecord, showStruct, xmlLin, latexLin, moduleOptDescr =
tableLin, useUTF8, showLang, withMetas :: Option [
defaultLinOpts :: [Option] 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 }
allLin = iOpt "all" optimize x = case lookup x optimizationPackages of
firstLin = iOpt "one" Just p -> set $ \o -> o { optOptimizations = p }
distinctLin = iOpt "nub" Nothing -> fail $ "Unknown optimization package: " ++ x
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 toggleOptimize x b = set $ \o -> o { optOptimizations = (if b then (x:) else delete x) (optOptimizations o) }
beVerbose, showInfo, beSilent, emitCode, getHelp, dumpOption s d = Option [] ["dump-"++s] (NoArg (set $ \o -> o { optDump = d:optDump o})) ("Dump output of the " ++ s ++ " phase.")
doMake, doBatch, notEmitCode, makeMulti, beShort,
wholeGrammar, makeFudget, byLines, byWords, analMorpho,
doTrace, noCPU, doCompute, optimizeCanon, optimizeValues,
stripQualif, nostripQualif, showAll, fromSource :: Option
beVerbose = iOpt "v" set = return . ModuleOptions
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 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 }
useUnicode, optCompute, optCheck, optParaphrase, forJava :: Option set = return . Options
useUnicode = iOpt "unicode" instance Functor OptDescr where
optCompute = iOpt "compute" fmap f (Option cs ss d s) = Option cs ss (fmap f d) s
optCheck = iOpt "typecheck"
optParaphrase = iOpt "paraphrase"
forJava = iOpt "java"
-- ** for edit session 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
allLangs, absView :: Option outputFormats :: [(String,OutputFormat)]
outputFormats =
[("gfcc", FmtGFCC),
("js", FmtJavaScript),
("haskell", FmtHaskell),
("haskell_gadt", FmtHaskellGADT)]
allLangs = iOpt "All" instance Show OutputFormat where
absView = iOpt "Abs" show = lookupShow outputFormats
-- ** options that take arguments instance Read OutputFormat where
readsPrec = lookupReadsPrec outputFormats
useTokenizer, useUntokenizer, useParser, withFun, optimizationPackages :: [(String,[Optimization])]
useLanguage, useResource, speechLanguage, useFont, optimizationPackages =
grammarFormat, grammarPrinter, filterString, termCommand, [("all_subs", [OptStem,OptCSE,OptExpand,OptParametrize,OptValues]), -- deprecated
transferFun, forForms, menuDisplay, sizeDisplay, typeDisplay, ("all", [OptStem,OptCSE,OptExpand,OptParametrize,OptValues]),
noDepTypes, extractGr, pathList, uniCoding :: String -> Option ("values", [OptStem,OptCSE,OptExpand,OptValues]),
-- | used on command line ("parametrize", [OptStem,OptCSE,OptExpand,OptParametrize]),
firstCat :: String -> Option ("none", [OptStem,OptCSE,OptExpand]),
-- | used in grammar, to avoid clash w res word ("noexpand", [OptStem,OptCSE])]
gStartCat :: String -> Option
useTokenizer = aOpt "lexer" encodings :: [(String,Encoding)]
useUntokenizer = aOpt "unlexer" encodings =
useParser = aOpt "parser" [("utf8", UTF_8),
-- useStrategy = aOpt "strategy" -- parsing strategy ("latin1", ISO_8859_1)]
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: lookupShow :: Eq a => [(String,a)] -> a -> String
gfcConversion :: String -> Option lookupShow xs z = fromMaybe "lookupShow" $ lookup z [(y,x) | (x,y) <- xs]
gfcConversion = aOpt "conversion"
useName, useAbsName, useCncName, useResName, lookupReadsPrec :: [(String,a)] -> Int -> ReadS a
useFile, useOptimizer :: String -> Option lookupReadsPrec xs _ s = [(z,rest) | (x,rest) <- lex s, (y,z) <- xs, y == x]
useName = aOpt "name" onOff :: Monad m => (Bool -> m a) -> Bool -> ArgDescr (m a)
useAbsName = aOpt "abs" onOff f def = OptArg g "[on,off]"
useCncName = aOpt "cnc" where g ma = maybe (return def) readOnOff ma >>= f
useResName = aOpt "res" readOnOff x = case map toLower x of
useFile = aOpt "file" "on" -> return True
useOptimizer = aOpt "optimize" "off" -> return False
_ -> fail $ "Expected [on,off], got: " ++ show x
markLin :: String -> Option readOutputFormat :: Monad m => String -> m OutputFormat
markOptXML, markOptJava, markOptStruct, markOptFocus :: String readOutputFormat s =
maybe (fail $ "Unknown output format: " ++ show s) return $ lookup s outputFormats
markLin = aOpt "mark" -- FIXME: this is a copy of the function in GF.Devel.UseIO.
markOptXML = oArg "xml" splitInModuleSearchPath :: String -> [FilePath]
markOptJava = oArg "java" splitInModuleSearchPath s = case break isPathSep s of
markOptStruct = oArg "struct" (f,_:cs) -> f : splitInModuleSearchPath cs
markOptFocus = oArg "focus" (f,_) -> [f]
where
isPathSep :: Char -> Bool
isPathSep c = c == ':' || c == ';'
--
-- * Convenience functions for checking options
--
-- ** refinement order beVerbose :: Options -> Bool
beVerbose = flag ((>= 3) . optVerbosity)
nextRefine :: String -> Option beSilent :: Options -> Bool
firstRefine, lastRefine :: String beSilent = flag ((<= 0) . optVerbosity)
nextRefine = aOpt "nextrefine" dump :: Options -> Dump -> Bool
firstRefine = oArg "first" dump opts d = moduleFlag ((d `elem`) . optDump) opts
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

View File

@@ -24,6 +24,7 @@ import System.FilePath
import System.IO import System.IO
import System.IO.Error import System.IO.Error
import System.Environment import System.Environment
import System.Exit
import System.CPUTime import System.CPUTime
import Control.Monad import Control.Monad
import Control.Exception(evaluate) import Control.Exception(evaluate)
@@ -39,20 +40,16 @@ putShow' f = putStrLn . show . length . show . f
putIfVerb :: Options -> String -> IO () putIfVerb :: Options -> String -> IO ()
putIfVerb opts msg = putIfVerb opts msg =
if oElem beVerbose opts if beVerbose opts
then putStrLn msg then putStrLn msg
else return () else return ()
putIfVerbW :: Options -> String -> IO () putIfVerbW :: Options -> String -> IO ()
putIfVerbW opts msg = putIfVerbW opts msg =
if oElem beVerbose opts if beVerbose opts
then putStr (' ' : msg) then putStr (' ' : msg)
else return () else return ()
-- | obsolete with IOE monad
errIO :: a -> Err a -> IO a
errIO = errOptIO noOptions
errOptIO :: Options -> a -> Err a -> IO a errOptIO :: Options -> a -> Err a -> IO a
errOptIO os e m = case m of errOptIO os e m = case m of
Ok x -> return x Ok x -> return x
@@ -235,6 +232,13 @@ foldIOE f s xs = case xs of
Ok v -> foldIOE f v xx Ok v -> foldIOE f v xx
Bad m -> return $ (s, Just m) Bad m -> return $ (s, Just m)
dieIOE :: IOE a -> IO a
dieIOE x = appIOE x >>= err die return
die :: String -> IO a
die s = do hPutStrLn stderr s
exitFailure
putStrLnE :: String -> IOE () putStrLnE :: String -> IOE ()
putStrLnE = ioeIO . putStrLnFlush putStrLnE = ioeIO . putStrLnFlush
@@ -243,28 +247,27 @@ putStrE = ioeIO . putStrFlush
-- this is more verbose -- this is more verbose
putPointE :: Options -> String -> IOE a -> IOE a putPointE :: Options -> String -> IOE a -> IOE a
putPointE = putPointEgen (oElem beSilent) putPointE = putPointEgen beSilent
-- this is less verbose -- this is less verbose
putPointEsil :: Options -> String -> IOE a -> IOE a putPointEsil :: Options -> String -> IOE a -> IOE a
putPointEsil = putPointEgen (not . oElem beVerbose) putPointEsil = putPointEgen (not . beVerbose)
putPointEgen :: (Options -> Bool) -> Options -> String -> IOE a -> IOE a putPointEgen :: (Options -> Bool) -> Options -> String -> IOE a -> IOE a
putPointEgen cond opts msg act = do putPointEgen cond opts msg act = do
let ve x = if cond opts then return () else x when (cond opts) $ ioeIO $ putStrFlush msg
ve $ ioeIO $ putStrFlush msg
t1 <- ioeIO $ getCPUTime t1 <- ioeIO $ getCPUTime
a <- act >>= ioeIO . evaluate a <- act >>= ioeIO . evaluate
t2 <- ioeIO $ getCPUTime t2 <- ioeIO $ getCPUTime
ve $ ioeIO $ putStrLnFlush (' ' : show ((t2 - t1) `div` 1000000000) ++ " msec") when (flag optShowCPUTime opts) $ ioeIO $ putStrLnFlush (' ' : show ((t2 - t1) `div` 1000000000) ++ " msec")
return a return a
-- | forces verbosity -- | forces verbosity
putPointEVerb :: Options -> String -> IOE a -> IOE a putPointEVerb :: Options -> String -> IOE a -> IOE a
putPointEVerb opts = putPointE (addOption beVerbose opts) putPointEVerb = putPointEgen (const False)
-- ((do {s <- readFile f; return (return s)}) ) -- ((do {s <- readFile f; return (return s)}) )
readFileIOE :: FilePath -> IOE BS.ByteString readFileIOE :: FilePath -> IOE BS.ByteString

View File

@@ -51,7 +51,7 @@ trModule (i,mo) = case mo of
body = P.MBody body = P.MBody
(trExtends (extend m)) (trExtends (extend m))
(mkOpens (map trOpen (opens m))) (mkOpens (map trOpen (opens m)))
(mkTopDefs (concatMap trAnyDef (tree2list (jments m)) ++ map trFlag (flags m))) (mkTopDefs (concatMap trAnyDef (tree2list (jments m)) ++ trFlags (flags m)))
trExtends :: [(Ident,MInclude Ident)] -> P.Extend trExtends :: [(Ident,MInclude Ident)] -> P.Extend
trExtends [] = P.NoExt trExtends [] = P.NoExt
@@ -130,11 +130,11 @@ trPerh p = case p of
May b -> P.EIndir $ tri b May b -> P.EIndir $ tri b
_ -> P.EMeta --- _ -> P.EMeta ---
trFlags :: ModuleOptions -> [P.TopDef]
trFlags = map trFlag . moduleOptionsGFO
trFlag :: Option -> P.TopDef trFlag :: (String,String) -> P.TopDef
trFlag o = case o of trFlag (f,x) = P.DefFlag [P.FlagDef (tri $ identC (BS.pack f)) (tri $ identC (BS.pack x))]
Opt (f,[x]) -> P.DefFlag [P.FlagDef (tri $ identC (BS.pack f)) (tri $ identC (BS.pack x))]
_ -> P.DefFlag [] --- warning?
trt :: Term -> P.Exp trt :: Term -> P.Exp
trt trm = case trm of trt trm = case trm of

View File

@@ -107,14 +107,14 @@ transModDef x = case x of
opens' <- transOpens opens opens' <- transOpens opens
defs0 <- mapM trDef $ getTopDefs defs defs0 <- mapM trDef $ getTopDefs defs
defs' <- U.buildAnyTree [d | Left ds <- defs0, d <- ds] defs' <- U.buildAnyTree [d | Left ds <- defs0, d <- ds]
flags' <- return [f | Right fs <- defs0, f <- fs] flags' <- return $ concatModuleOptions [o | Right o <- defs0]
return (id',GM.ModMod (GM.Module mtyp' mstat' flags' extends' opens' defs')) return (id',GM.ModMod (GM.Module mtyp' mstat' flags' extends' opens' defs'))
MReuse _ -> do MReuse _ -> do
return (id', GM.ModMod (GM.Module mtyp' mstat' [] [] [] emptyBinTree)) return (id', GM.ModMod (GM.Module mtyp' mstat' noModuleOptions [] [] emptyBinTree))
MUnion imps -> do MUnion imps -> do
imps' <- mapM transIncluded imps imps' <- mapM transIncluded imps
return (id', return (id',
GM.ModMod (GM.Module (GM.MTUnion mtyp' imps') mstat' [] [] [] emptyBinTree)) GM.ModMod (GM.Module (GM.MTUnion mtyp' imps') mstat' noModuleOptions [] [] emptyBinTree))
MWith m insts -> mkBody xx $ MWithEBody [] m insts NoOpens [] MWith m insts -> mkBody xx $ MWithEBody [] m insts NoOpens []
MWithBody m insts opens defs -> mkBody xx $ MWithEBody [] m insts opens defs MWithBody m insts opens defs -> mkBody xx $ MWithEBody [] m insts opens defs
@@ -126,7 +126,7 @@ transModDef x = case x of
opens' <- transOpens opens opens' <- transOpens opens
defs0 <- mapM trDef $ getTopDefs defs defs0 <- mapM trDef $ getTopDefs defs
defs' <- U.buildAnyTree [d | Left ds <- defs0, d <- ds] defs' <- U.buildAnyTree [d | Left ds <- defs0, d <- ds]
flags' <- return [f | Right fs <- defs0, f <- fs] flags' <- return $ concatModuleOptions [o | Right o <- defs0]
return (id', return (id',
GM.ModWith (GM.Module mtyp' mstat' flags' extends' opens' defs') m' insts') GM.ModWith (GM.Module mtyp' mstat' flags' extends' opens' defs') m' insts')
@@ -215,7 +215,7 @@ transIncludedExt x = case x of
ISome i ids -> liftM2 (,) (transIdent i) (liftM GM.MIOnly $ mapM transIdent ids) ISome i ids -> liftM2 (,) (transIdent i) (liftM GM.MIOnly $ mapM transIdent ids)
IMinus i ids -> liftM2 (,) (transIdent i) (liftM GM.MIExcept $ mapM transIdent ids) IMinus i ids -> liftM2 (,) (transIdent i) (liftM GM.MIExcept $ mapM transIdent ids)
transAbsDef :: TopDef -> Err (Either [(Ident, G.Info)] [GO.Option]) transAbsDef :: TopDef -> Err (Either [(Ident, G.Info)] GO.ModuleOptions)
transAbsDef x = case x of transAbsDef x = case x of
DefCat catdefs -> liftM (Left . concat) $ mapM transCatDef catdefs DefCat catdefs -> liftM (Left . concat) $ mapM transCatDef catdefs
DefFun fundefs -> do DefFun fundefs -> do
@@ -240,7 +240,7 @@ transAbsDef x = case x of
DefTrans defs -> do DefTrans defs -> do
defs' <- liftM concat $ mapM getDefsGen defs defs' <- liftM concat $ mapM getDefsGen defs
returnl [(c, G.AbsTrans f) | (c,(_,Yes f)) <- defs'] returnl [(c, G.AbsTrans f) | (c,(_,Yes f)) <- defs']
DefFlag defs -> liftM Right $ mapM transFlagDef defs DefFlag defs -> liftM (Right . concatModuleOptions) $ mapM transFlagDef defs
_ -> Bad $ "illegal definition in abstract module:" ++++ printTree x _ -> Bad $ "illegal definition in abstract module:" ++++ printTree x
where where
-- to get data constructors as terms -- to get data constructors as terms
@@ -253,9 +253,9 @@ transAbsDef x = case x of
returnl :: a -> Err (Either a b) returnl :: a -> Err (Either a b)
returnl = return . Left returnl = return . Left
transFlagDef :: FlagDef -> Err GO.Option transFlagDef :: FlagDef -> Err GO.ModuleOptions
transFlagDef x = case x of transFlagDef x = case x of
FlagDef f x -> return $ GO.Opt (prPIdent f,[prPIdent x]) FlagDef f x -> parseModuleOptions ["--" ++ prPIdent f ++ "=" ++ prPIdent x]
where where
prPIdent (PIdent (_,c)) = BS.unpack c prPIdent (PIdent (_,c)) = BS.unpack c
@@ -306,7 +306,7 @@ transDataDef x = case x of
DataId id -> liftM G.Cn $ transIdent id DataId id -> liftM G.Cn $ transIdent id
DataQId id0 id -> liftM2 G.QC (transIdent id0) (transIdent id) DataQId id0 id -> liftM2 G.QC (transIdent id0) (transIdent id)
transResDef :: TopDef -> Err (Either [(Ident, G.Info)] [GO.Option]) transResDef :: TopDef -> Err (Either [(Ident, G.Info)] GO.ModuleOptions)
transResDef x = case x of transResDef x = case x of
DefPar pardefs -> do DefPar pardefs -> do
pardefs' <- mapM transParDef pardefs pardefs' <- mapM transParDef pardefs
@@ -332,7 +332,7 @@ transResDef x = case x of
defs' <- liftM concat $ mapM getDefs defs defs' <- liftM concat $ mapM getDefs defs
returnl [(f, G.ResOper pt pe) | (f,(pt,pe)) <- defs'] returnl [(f, G.ResOper pt pe) | (f,(pt,pe)) <- defs']
DefFlag defs -> liftM Right $ mapM transFlagDef defs DefFlag defs -> liftM (Right . concatModuleOptions) $ mapM transFlagDef defs
_ -> Bad $ "illegal definition form in resource" +++ printTree x _ -> Bad $ "illegal definition form in resource" +++ printTree x
where where
mkOverload (c,j) = case j of mkOverload (c,j) = case j of
@@ -354,7 +354,7 @@ transParDef x = case x of
ParDefAbs id -> liftM2 (,) (transIdent id) (return []) ParDefAbs id -> liftM2 (,) (transIdent id) (return [])
_ -> Bad $ "illegal definition in resource:" ++++ printTree x _ -> Bad $ "illegal definition in resource:" ++++ printTree x
transCncDef :: TopDef -> Err (Either [(Ident, G.Info)] [GO.Option]) transCncDef :: TopDef -> Err (Either [(Ident, G.Info)] GO.ModuleOptions)
transCncDef x = case x of transCncDef x = case x of
DefLincat defs -> do DefLincat defs -> do
defs' <- liftM concat $ mapM transPrintDef defs defs' <- liftM concat $ mapM transPrintDef defs
@@ -374,7 +374,7 @@ transCncDef x = case x of
DefPrintOld defs -> do --- a guess, for backward compatibility DefPrintOld defs -> do --- a guess, for backward compatibility
defs' <- liftM concat $ mapM transPrintDef defs defs' <- liftM concat $ mapM transPrintDef defs
returnl [(f, G.CncFun Nothing nope (yes e)) | (f,e) <- defs'] returnl [(f, G.CncFun Nothing nope (yes e)) | (f,e) <- defs']
DefFlag defs -> liftM Right $ mapM transFlagDef defs DefFlag defs -> liftM (Right . concatModuleOptions) $ mapM transFlagDef defs
DefPattern defs -> do DefPattern defs -> do
defs' <- liftM concat $ mapM getDefs defs defs' <- liftM concat $ mapM getDefs defs
let defs2 = [(f, termInPattern t) | (f,(_,Yes t)) <- defs'] let defs2 = [(f, termInPattern t) | (f,(_,Yes t)) <- defs']
@@ -700,10 +700,10 @@ transOldGrammar opts name0 x = case x of
ne = NoExt ne = NoExt
q = CMCompl q = CMCompl
name = maybe name0 (++ ".gf") $ getOptVal opts useName name = maybe name0 (++ ".gf") $ moduleFlag optName opts
absName = identPI $ maybe topic id $ getOptVal opts useAbsName absName = identPI $ maybe topic id $ moduleFlag optAbsName opts
resName = identPI $ maybe ("Res" ++ lang) id $ getOptVal opts useResName resName = identPI $ maybe ("Res" ++ lang) id $ moduleFlag optResName opts
cncName = identPI $ maybe lang id $ getOptVal opts useCncName cncName = identPI $ maybe lang id $ moduleFlag optCncName opts
identPI s = PIdent ((0,0),BS.pack s) identPI s = PIdent ((0,0),BS.pack s)

View File

@@ -12,56 +12,40 @@ import GF.Infra.Option
import GF.GFCC.API import GF.GFCC.API
import GF.Data.ErrM import GF.Data.ErrM
import Data.Maybe
import System.FilePath import System.FilePath
mainGFC :: [String] -> IO ()
mainGFC xx = do
let (opts,fs) = getOptions "-" xx
case opts of
_ | oElem (iOpt "help") opts -> putStrLn usageMsg
_ | oElem (iOpt "-make") opts -> do
gfcc <- appIOE (compileToGFCC opts fs) >>= err fail return
let gfccFile = targetNameGFCC opts (absname gfcc)
outputFile gfccFile (printGFCC gfcc)
mapM_ (alsoPrint opts gfcc) printOptions
-- gfc -o target.gfcc source_1.gfcc ... source_n.gfcc mainGFC :: Options -> [FilePath] -> IOE ()
_ | all ((==".gfcc") . takeExtensions) fs -> do mainGFC opts fs =
gfccs <- mapM file2gfcc fs do gr <- batchCompile opts fs
let gfcc = foldl1 unionGFCC gfccs let cnc = justModuleName (last fs)
let gfccFile = targetNameGFCC opts (absname gfcc) if flag optStopAfterPhase opts == Compile
outputFile gfccFile (printGFCC gfcc) then return ()
mapM_ (alsoPrint opts gfcc) printOptions else do gfcc <- link opts cnc gr
writeOutputs opts gfcc
_ -> do
appIOE (mapM_ (batchCompile opts) (map return fs)) >>= err fail return
putStrLn "Done."
targetName :: Options -> CId -> String writeOutputs :: Options -> GFCC -> IOE ()
targetName opts abs = case getOptVal opts (aOpt "target") of writeOutputs opts gfcc = mapM_ (\fmt -> writeOutput opts fmt gfcc) (flag optOutputFormats opts)
Just n -> n
_ -> prCId abs
targetNameGFCC :: Options -> CId -> FilePath writeOutput :: Options -> OutputFormat-> GFCC -> IOE ()
targetNameGFCC opts abs = targetName opts abs ++ ".gfcc" writeOutput opts fmt gfcc =
do let path = outputFilePath opts fmt (prCId (absname gfcc))
s = prGFCC fmt gfcc
writeOutputFile path s
---- TODO: nicer and richer print options outputFilePath :: Options -> OutputFormat -> String -> FilePath
outputFilePath opts fmt name0 = addDir name <.> fmtExtension fmt
where name = fromMaybe name0 (moduleFlag optName opts)
addDir = maybe id (</>) (flag optOutputDir opts)
alsoPrint opts gr (opt,name) = do fmtExtension :: OutputFormat -> String
if oElem (iOpt opt) opts fmtExtension FmtGFCC = "gfcc"
then outputFile name (prGFCC opt gr) fmtExtension FmtJavaScript = "js"
else return () fmtExtension FmtHaskell = "hs"
fmtExtension FmtHaskellGADT = "hs"
outputFile :: FilePath -> String -> IO () writeOutputFile :: FilePath -> String -> IOE ()
outputFile outfile output = writeOutputFile outfile output = ioeIO $
do writeFile outfile output do writeFile outfile output
putStrLn $ "wrote file " ++ outfile putStrLn $ "wrote file " ++ outfile
printOptions = [
("haskell","GSyntax.hs"),
("haskell_gadt","GSyntax.hs"),
("js","grammar.js")
]
usageMsg =
"usage: gfc (-h | --make (-noopt) (-noparse) (-target=PREFIX) (-js | -haskell | -haskell_gadt)) (-src) FILES"

View File

@@ -3,12 +3,12 @@ module GFI (mainGFI) where
import GF.Command.Interpreter import GF.Command.Interpreter
import GF.Command.Importing import GF.Command.Importing
import GF.Command.Commands import GF.Command.Commands
import GF.Data.ErrM
import GF.GFCC.API import GF.GFCC.API
import GF.Grammar.API -- for cc command import GF.Grammar.API -- for cc command
import GF.Infra.UseIO import GF.Infra.UseIO
import GF.Infra.Option ---- Haskell's option lib import GF.Infra.Option
import GF.System.Readline (fetchCommand) import GF.System.Readline (fetchCommand)
import System.CPUTime import System.CPUTime
@@ -17,10 +17,10 @@ import Data.Version
import Paths_gf import Paths_gf
mainGFI :: [String] -> IO () mainGFI :: Options -> [FilePath] -> IO ()
mainGFI xx = do mainGFI opts files = do
putStrLn welcome putStrLn welcome
env <- importInEnv emptyMultiGrammar xx env <- importInEnv emptyMultiGrammar opts files
loop (GFEnv emptyGrammar env [] 0) loop (GFEnv emptyGrammar env [] 0)
return () return ()
@@ -31,25 +31,26 @@ loop gfenv0 = do
s <- fetchCommand (prompt env) s <- fetchCommand (prompt env)
let gfenv = gfenv0 {history = s : history gfenv0} let gfenv = gfenv0 {history = s : history gfenv0}
case words s of case words s of
-- special commands, requiring source grammar in env -- special commands, requiring source grammar in env
"cc":ws -> do "cc":ws -> do
let (opts,term) = getOptions "-" ws -- FIXME: add options parsing for cc arguments
let (opts,term) = (TermPrintDefault, ws)
let t = pTerm (unwords term) >>= checkTerm sgr >>= computeTerm sgr let t = pTerm (unwords term) >>= checkTerm sgr >>= computeTerm sgr
err putStrLn (putStrLn . showTerm opts) t ---- make pipable err putStrLn (putStrLn . showTerm opts) t ---- make pipable
loopNewCPU gfenv loopNewCPU gfenv
"i":args -> do "i":args -> do
let (opts,files) = getOptions "-" args case parseOptions args of
case opts of Ok (opts,files)
_ | oElem (iOpt "retain") opts -> do | flag optRetainResource opts ->
src <- importSource sgr opts files do src <- importSource sgr opts files
loopNewCPU $ gfenv {sourcegrammar = src} loopNewCPU $ gfenv {sourcegrammar = src}
| otherwise ->
do env1 <- importInEnv (multigrammar env) opts files
loopNewCPU $ gfenv {commandenv = env1}
Bad err -> do putStrLn $ "Command parse error: " ++ err
loopNewCPU gfenv
-- other special commands, working on GFEnv -- other special commands, working on GFEnv
_ -> do
env1 <- importInEnv (multigrammar env) args
loopNewCPU $ gfenv {commandenv = env1}
"e":_ -> loopNewCPU $ gfenv {commandenv=env{multigrammar=emptyMultiGrammar}} "e":_ -> loopNewCPU $ gfenv {commandenv=env{multigrammar=emptyMultiGrammar}}
"ph":_ -> mapM_ putStrLn (reverse (history gfenv0)) >> loopNewCPU gfenv "ph":_ -> mapM_ putStrLn (reverse (history gfenv0)) >> loopNewCPU gfenv
"q":_ -> putStrLn "See you." >> return gfenv "q":_ -> putStrLn "See you." >> return gfenv
@@ -64,8 +65,8 @@ loopNewCPU gfenv = do
putStrLn (show ((cpu' - cputime gfenv) `div` 1000000000) ++ " msec") putStrLn (show ((cpu' - cputime gfenv) `div` 1000000000) ++ " msec")
loop $ gfenv {cputime = cpu'} loop $ gfenv {cputime = cpu'}
importInEnv mgr0 xx = do importInEnv :: MultiGrammar -> Options -> [FilePath] -> IO CommandEnv
let (opts,files) = getOptions "-" xx importInEnv mgr0 opts files = do
mgr1 <- case files of mgr1 <- case files of
[] -> return mgr0 [] -> return mgr0
_ -> importGrammar mgr0 opts files _ -> importGrammar mgr0 opts files