import Prelude hiding (head, init, last, reverse, tail) import qualified Prelude import Data.Char (isDigit) import Data.Foldable (for_) import Data.List (intercalate, intersperse, isPrefixOf, replicate, stripPrefix) import Distribution.Simple (Args, UserHooks (preBuild), defaultMainWithHooks, simpleUserHooks) import Distribution.Simple.Setup (BuildFlags) import Distribution.Types.HookedBuildInfo (HookedBuildInfo, emptyHookedBuildInfo) import System.Directory (copyFile, createDirectoryIfMissing, getTemporaryDirectory, removeFile) import System.IO (Handle, IOMode (ReadMode), hClose, hGetLine, hIsEOF, hPutStrLn, hSetNewlineMode, noNewlineTranslation, openTempFile, stdin, withFile) main :: IO () main = defaultMainWithHooks simpleUserHooks { preBuild = preProcessListTuple } preProcessListTuple :: Args -> BuildFlags -> IO HookedBuildInfo preProcessListTuple _ _ = do let dir = "src/Data/Tuple" file = "Homotuple.hs" srcPath = dir ++ "/" ++ file templatePath = "template/Homotuple.hs" templateItemPath = "template/HomotupleItem.hs" tempPath <- withFile templatePath ReadMode $ \template -> do tempDir <- (++ "/homotuple") <$> getTemporaryDirectory createDirectoryIfMissing True tempDir (tempPath, temp) <- openTempFile tempDir file putStrLn $ "temporaly file: " ++ tempPath hSetNewlineMode template noNewlineTranslation hSetNewlineMode temp noNewlineTranslation hSetNewlineMode stdin noNewlineTranslation templateItem <- lines <$> readFile templateItemPath loop template temp templateItem hClose temp pure tempPath copyFile tempPath srcPath removeFile tempPath pure emptyHookedBuildInfo where loop :: Handle -> Handle -> [String] -> IO () loop template temp templateItem = go where go = do eof <- hIsEOF template if eof then pure () else do line <- hGetLine template for_ (preprocess line templateItem) (hPutStrLn temp) go preprocess :: String -> [String] -> [String] preprocess line templateItem | Just rest <- stripPrefix "---- embed " line , let n = read $ takeWhile isDigit rest = embed n templateItem | otherwise = [line] embed :: Word -> [String] -> [String] embed l templateItem | l >= 2 = concatMap go templateItem | otherwise = error "length must be larger than or equal to 2" where go "" = [""] go t | Just rest <- stripPrefix "" t = [homotuple ++ Prelude.head (go rest)] | Just rest <- stripPrefix "" t = [tuple ++ Prelude.head (go rest)] | Just rest <- stripPrefix "" t = [list ++ Prelude.head (go rest)] | Just rest <- stripPrefix "" t = [length ++ Prelude.head (go rest)] | Just rest <- stripPrefix "<" t = error $ "unknown tag: " ++ takeWhile (/= '>') rest | (s, rest) <- span (/= '<') t = [s ++ Prelude.head (go rest)] n = fromIntegral l homotuple = paren $ replicate n "a" tuple = paren $ take n i012 list = bracket $ take n i012 length = show l paren xs = "(" ++ intercalate ", " xs ++ ")" bracket xs = "[" ++ intercalate ", " xs ++ "]" i012 = ('i':) . show <$> [0 ..]