1
0
forked from GitHub/gf-core
Files
gf-core/Setup.hs

317 lines
12 KiB
Haskell

module Main where
import Distribution.Simple
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.BuildPaths
import Distribution.Simple.Utils
import Distribution.Simple.Setup
import Distribution.PackageDescription hiding (Flag)
import Control.Monad
import Data.Maybe
import Data.List(isPrefixOf)
import System.IO
import System.Cmd
import System.FilePath
import System.Directory
import System.Environment
import System.Process
import System.Exit
main :: IO ()
main = defaultMainWithHooks simpleUserHooks{ preBuild =checkRGLArgs
, postBuild=buildRGL
, preInst =checkRGLArgs
, postInst =installRGL
, preCopy =checkRGLArgs
, postCopy =copyRGL
, sDistHook=sdistRGL
, runTests =testRGL
}
--------------------------------------------------------
-- Commands for building the Resource Grammar Library
--------------------------------------------------------
data Mode
= AllTenses
| Present
| Minimal
deriving Show
data RGLCommand
= RGLCommand
{ cmdName :: String
, cmdIsDef :: Bool
, cmdAction :: Mode -> [String] -> PackageDescription -> LocalBuildInfo -> IO ()
}
rglCommands =
[ RGLCommand "prelude" True $ \mode args pkg lbi -> do
putStrLn $ "Compiling [prelude]"
let prelude_src_dir = rgl_src_dir </> "prelude"
prelude_dst_dir = rgl_dst_dir lbi </> "prelude"
createDirectoryIfMissing True prelude_dst_dir
files <- getDirectoryContents prelude_src_dir
run_gfc pkg lbi (["-s", "--gfo-dir="++prelude_dst_dir] ++ [prelude_src_dir </> file | file <- files, take 1 file /= "."])
, RGLCommand "lang" True $ \mode args pkg lbi -> do
mapM_ (gfc mode pkg lbi . lang) (optl langsLang args)
mapM_ (gfc mode pkg lbi . symbol) (optl langsAPI args)
, RGLCommand "compat" True $ \mode args pkg lbi -> do
mapM_ (gfc mode pkg lbi . compat) (optl langsCompat args)
, RGLCommand "api" True $ \mode args pkg lbi -> do
mapM_ (gfc mode pkg lbi . try) (optl langsAPI args)
mapM_ (gfc mode pkg lbi . symbolic) (optl langsAPI args)
, RGLCommand "pgf" False $ \mode args pkg lbi -> do
let dir = getRGLBuildDir lbi mode
createDirectoryIfMissing True dir
sequence_ [run_gfc pkg lbi ["-s","-make","-name=Lang"++la,dir ++ "/Lang" ++ la ++ ".gfo"] | (_,la) <- optl langsPGF args]
run_gfc pkg lbi (["-s","-make","-name=Lang"]++["Lang" ++ la ++ ".pgf" | (_,la) <- optl langsPGF args])
, RGLCommand "demo" False $ \mode args pkg lbi -> do
let ls = optl langsDemo args
gf (demos "Demo" ls) ["demo/Demo" ++ la ++ ".gf" | (_,la) <- ls] pkg lbi
return ()
, RGLCommand "parse" False $ \mode args pkg lbi -> do
mapM_ (gfc mode pkg lbi . parse) (optl langsParse args)
, RGLCommand "none" False $ \mode args pkg lbi -> do
return ()
]
where
optl ls args = fromMaybe ls $ getOptLangs args
--------------------------------------------------------
checkRGLArgs args flags = do
let args' = filter (\arg -> not (arg == "present" ||
arg == "minimal" ||
rgl_prefix `isPrefixOf` arg ||
langs_prefix `isPrefixOf` arg)) args
if null args'
then return emptyHookedBuildInfo
else die $ "Unrecognised flags: " ++ intercalate ", " args'
buildRGL args flags pkg lbi = do
let cmds = getRGLCommands args
let mode = getOptMode args
mapM_ (\cmd -> cmdAction cmd mode args pkg lbi) cmds
installRGL args flags pkg lbi = do
let mode = getOptMode args
let inst_gf_lib_dir = datadir (absoluteInstallDirs pkg lbi NoCopyDest) </> "lib"
copyAll "prelude" (rgl_dst_dir lbi </> "prelude") (inst_gf_lib_dir </> "prelude")
copyAll (show mode) (getRGLBuildDir lbi mode) (inst_gf_lib_dir </> getRGLBuildSubDir lbi mode)
copyRGL args flags pkg lbi = do
let mode = getOptMode args
dest = case copyDest flags of
NoFlag -> NoCopyDest
Flag d -> d
let inst_gf_lib_dir = datadir (absoluteInstallDirs pkg lbi dest) </> "lib"
copyAll "prelude" (rgl_dst_dir lbi </> "prelude") (inst_gf_lib_dir </> "prelude")
copyAll (show mode) (getRGLBuildDir lbi mode) (inst_gf_lib_dir </> getRGLBuildSubDir lbi mode)
copyAll s from to = do
putStrLn $ "Installing [" ++ s ++ "] " ++ to
createDirectoryIfMissing True to
files <- fmap (filter (\f -> take 1 f /= ".")) $ getDirectoryContents from
mapM_ (\file -> copyFile (from </> file) (to </> file)) files
sdistRGL pkg mb_lbi hooks flags = do
paths <- getRGLFiles rgl_src_dir []
let pkg' = pkg{dataFiles=paths}
sDistHook simpleUserHooks pkg' mb_lbi hooks flags
where
getRGLFiles dir paths = do
files <- getDirectoryContents dir
foldM (processFile dir) paths [file | file <- files, file /= "." && file /= ".."]
processFile dir paths file = do
let path = dir </> file
print path
isFile <- doesFileExist path
if isFile
then if takeExtension file == ".gf" || file == "LICENSE"
then return (path : paths)
else return paths
else getRGLFiles path paths
testRGL args _ pkg lbi = do
let paths = case args of
[] -> ["testsuite"]
paths -> paths
sequence_ [walk path | path <- paths]
where
walk path = do
files <- getDirectoryContents path
sequence_ [walkFile (path </> file) | file <- files, file /= "." && file /= ".."]
walkFile fpath = do
exists <- doesFileExist fpath
if exists
then if takeExtension fpath == ".gfs"
then do let in_file = fpath
gold_file = addExtension fpath ".gold"
out_file = addExtension fpath ".out"
putStr (in_file++" ... ")
hFlush stdout
res <- runTest in_file out_file gold_file
putStrLn (if res then "OK" else "FAIL")
else return ()
else walk fpath
runTest in_file out_file gold_file = do
inp <- readFile in_file
out <- readProcess (default_gf pkg lbi) ["-run"] inp
writeFile out_file out
exists <- doesFileExist gold_file
if exists
then do gold <- readFile gold_file
return $! (out == gold)
else return False
rgl_src_dir = "lib" </> "src"
rgl_dst_dir lbi = buildDir lbi </> "rgl"
-- the languages have long directory names and short ISO codes (3 letters)
-- we also give the decodings for postprocessing linearizations, as long as grammars
-- don't support all flags needed; they are used in tests
langsCoding = [
(("amharic", "Amh"),""),
(("arabic", "Ara"),""),
(("bulgarian","Bul"),""),
(("catalan", "Cat"),""),
(("danish", "Dan"),""),
(("dutch", "Dut"),""),
(("english", "Eng"),""),
(("finnish", "Fin"),""),
(("french", "Fre"),""),
(("hindi", "Hin"),"to_devanagari"),
(("german", "Ger"),""),
(("interlingua","Ina"),""),
(("italian", "Ita"),""),
(("latin", "Lat"),""),
(("norwegian","Nor"),""),
(("polish", "Pol"),""),
(("romanian", "Ron"),""),
(("russian", "Rus"),""),
(("spanish", "Spa"),""),
(("swedish", "Swe"),""),
(("thai", "Tha"),"to_thai"),
(("turkish", "Tur"),""),
(("urdu", "Urd"),"")
]
langs = map fst langsCoding
-- languagues for which to compile Lang
langsLang = langs `except` ["Amh","Ara","Lat","Hin","Tha","Tur"]
-- languages for which to compile Try
langsAPI = langsLang `except` ["Hin","Ina","Rus","Tha"]
-- languages for which to run demo test
langsDemo = langsLang `except` ["Ara","Hin","Ina","Tha"]
-- languages for which to compile parsing grammars
langsParse = langs `only` ["Eng"]
-- languages for which langs.pgf is built
langsPGF = langsLang `except` ["Ara","Hin","Ron","Tha"]
-- languages for which Compatibility exists (to be extended)
langsCompat = langsLang `only` ["Cat","Eng","Fin","Fre","Ita","Spa","Swe"]
gfc mode pkg lbi file = do
let dir = getRGLBuildDir lbi mode
preproc = case mode of
AllTenses -> ""
Present -> "-preproc="++({-rgl_src_dir </>-} "mkPresent")
Minimal -> "-preproc="++({-rgl_src_dir </>-} "mkMinimal")
createDirectoryIfMissing True dir
putStrLn $ "Compiling [" ++ show mode ++ "] " ++ file
run_gfc pkg lbi ["-s", preproc, "--gfo-dir="++dir, file]
gf comm files pkg lbi = do
putStrLn $ "Reading " ++ unwords files
let gf = default_gf pkg lbi
putStrLn ("executing: " ++ comm ++ "\n" ++
"in " ++ gf)
out <- readProcess gf ("-s":files) comm
putStrLn out
demos abstr ls = "gr -number=100 | l -treebank " ++ unlexer abstr ls ++
" | ps -to_html | wf -file=resdemo.html"
lang (lla,la) = rgl_src_dir </> lla </> ("All" ++ la ++ ".gf")
compat (lla,la) = rgl_src_dir </> lla </> ("Compatibility" ++ la ++ ".gf")
symbol (lla,la) = rgl_src_dir </> lla </> ("Symbol" ++ la ++ ".gf")
try (lla,la) = rgl_src_dir </> "api" </> ("Try" ++ la ++ ".gf")
syntax (lla,la) = rgl_src_dir </> "api" </> ("Syntax" ++ la ++ ".gf")
symbolic (lla,la) = rgl_src_dir </> "api" </> ("Symbolic" ++ la ++ ".gf")
parse (lla,la) = rgl_src_dir </> "parse" </> ("Parse" ++ la ++ ".gf")
except ls es = filter (flip notElem es . snd) ls
only ls es = filter (flip elem es . snd) ls
getOptMode args
| elem "present" args = Present
| elem "minimal" args = Minimal
| otherwise = AllTenses
-- list of languages overriding the definitions above
getOptLangs args = case [ls | arg <- args, let (f,ls) = splitAt (length langs_prefix) arg, f==langs_prefix] of
ls:_ -> return $ findLangs $ seps ls
_ -> Nothing
where
seps = words . map (\c -> if c==',' then ' ' else c)
findLangs ls = [lang | lang@(_,la) <- langs, elem la ls]
getRGLBuildSubDir lbi mode =
case mode of
AllTenses -> "alltenses"
Present -> "present"
Minimal -> "minimal"
getRGLBuildDir lbi mode = rgl_dst_dir lbi </> getRGLBuildSubDir lbi mode
getRGLCommands args =
let cmds0 = [cmd | arg <- args,
let (prefix,name) = splitAt (length rgl_prefix) arg,
prefix == rgl_prefix,
cmd <- rglCommands,
cmdName cmd == name]
in if null cmds0
then [cmd | cmd <- rglCommands, cmdIsDef cmd]
else cmds0
langs_prefix = "langs="
rgl_prefix = "rgl-"
unlexer abstr ls =
"-unlexer=\\\"" ++ unwords
[abstr ++ la ++ "=" ++ unl |
lla@(_,la) <- ls, let unl = unlex lla, not (null unl)] ++
"\\\""
where
unlex lla = maybe "" id $ lookup lla langsCoding
-- | Runs the gf executable in compile mode with the given arguments.
run_gfc :: PackageDescription -> LocalBuildInfo -> [String] -> IO ()
run_gfc pkg lbi args =
do let args' = ["-batch","-src","-gf-lib-path="++rgl_src_dir,"+RTS","-K32M","-RTS"] ++ filter (not . null) args
gf = default_gf pkg lbi
putStrLn $ "Running: " ++ gf ++ " " ++ unwords (map showArg args')
e <- rawSystem gf args'
case e of
ExitSuccess -> return ()
ExitFailure i -> die $ "gf exited with exit code: " ++ show i
where showArg arg = "'" ++ arg ++ "'"
default_gf pkg lbi = buildDir lbi </> exeName' </> exeNameReal
where
exeName' = (exeName . head . executables) pkg
exeNameReal = exeName' <.> (if null $ takeExtension exeName' then exeExtension else "")