1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
{-# LANGUAGE FlexibleContexts #-}
module Main where
import System.Directory
import Control.Monad
import Data.List
import Text.Parsec
import Control.Monad.IO.Class
import Data.Maybe
data LuaCode =
Comments String
| LuaLocString LuaCode LuaCode
| LuaString String LuaCode
| CodeChunk String LuaCode
| LuaOp String LuaCode
| BlocksList Char [LuaCode]
| NoCode
deriving (Show, Eq)
toChunk a = CodeChunk a NoCode
isLuaString LuaLocString{} = True
isLuaString LuaString{} = True
isLuaString _ = False
isLocString (BlocksList _ blocks) = or $ map isLocString blocks
isLocString LuaLocString{} = True
isLocString (LuaString _ lc) = isLocString lc
isLocString (CodeChunk _ lc) = isLocString lc
isLocString (LuaOp _ lc) = isLocString lc
isLocString _ = False
many1Till :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
many1Till p end = do
res <- scan
if null res then unexpected "many1Till" else return res
where
scan = do{ end; return [] }
<|>
do{ x <- p; xs <- scan; return (x:xs) }
processScript :: String -> IO [LuaCode]
processScript fileName = do
r <- runParserT processFile () "" ""
case r of
(Left a) -> do
putStrLn $ "Error: " ++ (show a)
return []
(Right a) -> return a
where
processFile = do
--liftIO $ putStrLn $ "Processing: " ++ fileName
f <- liftIO (readFile fileName)
setInput f
process
comment :: ParsecT String u IO LuaCode
comment = liftM Comments $ choice [
(try $ string "--[[") >> manyTill anyChar (try $ string "]]") >>= \s -> return $ "--[[" ++ s ++ "]]"
, (try $ string "--") >> manyTill anyChar (try newline) >>= \s -> return $ "--" ++ s ++ "\n"
]
stringConcat :: ParsecT String u IO ()
stringConcat = try $ string ".." >> spaces
locString :: ParsecT String u IO LuaCode
locString = do
s <- (try $ optional stringConcat >> string "loc(") >> luaString >>= \s -> char ')' >> return s
subString <- liftM (fromMaybe NoCode) . optionMaybe . try $ spaces >> string ".." >> spaces >> codeBlock
return $ LuaLocString s subString
luaString :: ParsecT String u IO LuaCode
luaString = do
s <- choice[
(try $ optional stringConcat >> char '\'') >> many (noneOf "'\n") >>= \s -> char '\'' >> return s
, (try $ optional stringConcat >> char '"') >> many (noneOf "\"\n") >>= \s -> char '"' >> return s
]
subString <- liftM (fromMaybe NoCode) . optionMaybe . try $ spaces >> string ".." >> spaces >> codeBlock
return $ LuaString s subString
luaOp :: ParsecT String u IO LuaCode
luaOp = do
s <- many1Till anyChar (lookAhead $ (oneOf "=-.,()[]{}'\"" >> return ()) <|> (try (string "end") >> return ()))
subCode <- liftM (fromMaybe NoCode) . optionMaybe . try $ codeBlock
return $ LuaOp s subCode
codeBlock :: ParsecT String u IO LuaCode
codeBlock = do
s <- choice [
comment
, liftM toChunk $ many1 space
, locString
, luaString
, luaOp
, liftM (BlocksList '[') . brackets $ commaSep luaOp
, liftM (BlocksList '{') . braces $ commaSep luaOp
, liftM (BlocksList '(') . parens $ commaSep luaOp
]
return s
brackets = between (char '[') (char ']')
braces = between (char '{') (char '}')
parens = between (char '(') (char ')')
commaSep p = p `sepBy` (char ',')
otherStuff :: ParsecT String u IO LuaCode
otherStuff = liftM (\s -> CodeChunk s NoCode) $ manyTill anyChar (try $ lookAhead codeBlock)
process :: ParsecT String u IO [LuaCode]
process = do
codes <- many $ try $ do
a <- otherStuff
b <- liftM (fromMaybe (CodeChunk "" NoCode)) $ optionMaybe $ try codeBlock
return [a, b]
liftIO . putStrLn . unlines . map (renderLua . processLocString) . filter isLocString $ concat codes
return $ concat codes
listFilesRecursively :: FilePath -> IO [FilePath]
listFilesRecursively dir = do
fs <- liftM (map (\d -> dir ++ ('/' : d)) . filter ((/=) '.' . head)) $ getDirectoryContents dir
dirs <- filterM doesDirectoryExist fs
recfs <- mapM listFilesRecursively dirs
return . concat $ fs : recfs
renderLua :: LuaCode -> String
renderLua (Comments str) = str
renderLua (LuaLocString lc1 lc2) = let r = renderLua lc2 in "loc(" ++ renderLua lc1 ++ ")" ++ r
renderLua (LuaString str lc) = let r = renderLua lc in "\"" ++ str ++ "\"" ++ r
renderLua (CodeChunk str lc) = str ++ renderLua lc
renderLua (LuaOp str lc) = str ++ renderLua lc
renderLua (BlocksList t lcs) = t : (concat . intersperse "," . map renderLua) lcs ++ [mirror t]
renderLua NoCode = ""
processLocString :: LuaCode -> LuaCode
processLocString lcode = let (str, params) = pp lcode in
LuaLocString (LuaString str NoCode)
(if null params then NoCode else (CodeChunk ".format" $ BlocksList '(' params))
where
pp (Comments _) = ("", [])
pp (LuaLocString lc1 lc2) = let (s1, p1) = pp lc1; (s2, p2) = pp lc2 in (s1 ++ s2, p1 ++ p2)
pp (LuaString str lc) = let (s, p) = pp lc in (str ++ s, p)
pp (CodeChunk str lc) = let (s, p) = pp lc in ("%s" ++ s, p)
pp (LuaOp str lc) = let (s, p) = pp lc in ("%s" ++ s, [LuaOp str (head $ p ++ [NoCode])])
pp (BlocksList t lcs) = ("", [BlocksList t lcs])
pp NoCode = ("", [])
mirror '(' = ')'
mirror '[' = ']'
mirror '{' = '}'
main = do
(l18ns, scripts) <- liftM (partition (isPrefixOf "share/hedgewars/Data/Locale") . filter (isSuffixOf ".lua"))
$ listFilesRecursively "share/hedgewars/Data"
mapM_ processScript scripts
--putStrLn $ unlines l18ns
|