{-# LANGUAGE FlexibleInstances #-}
module BNFC.Backend.Base
( Backend
, MkFiles
, GeneratedFile(..)
, MakeComment
, execBackend
, mkfile
, liftIO
, writeFiles
) where
import Control.Arrow ( (&&&) )
import Control.Monad.IO.Class ( liftIO )
import Control.Monad.Writer ( WriterT, execWriterT, tell )
import Data.Char ( isSpace )
import Data.Foldable ( forM_ )
import Data.Function ( on )
import qualified Data.List as List
import System.Directory ( createDirectoryIfMissing )
import System.FilePath ( dropFileName, takeExtension, (</>) )
import BNFC.Options ( versionString )
import BNFC.PrettyPrint
import BNFC.Utils ( writeFileRep )
msgGenerated :: String
msgGenerated :: String
msgGenerated = String
"File generated by the BNF Converter (bnfc " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
versionString String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")."
type MkFiles a = WriterT [GeneratedFile] IO a
type Backend = MkFiles ()
data GeneratedFile = GeneratedFile
{ GeneratedFile -> String
fileName :: FilePath
, :: MakeComment
, GeneratedFile -> String
fileContent :: String
}
instance Show GeneratedFile where
show :: GeneratedFile -> String
show (GeneratedFile String
x String -> String
_ String
y) = [String] -> String
unwords [ String
"GeneratedFile", String -> String
forall a. Show a => a -> String
show String
x, String
"_", String -> String
forall a. Show a => a -> String
show String
y ]
instance Eq GeneratedFile where
== :: GeneratedFile -> GeneratedFile -> Bool
(==) = (String, String) -> (String, String) -> Bool
forall a. Eq a => a -> a -> Bool
(==) ((String, String) -> (String, String) -> Bool)
-> (GeneratedFile -> (String, String))
-> GeneratedFile
-> GeneratedFile
-> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` GeneratedFile -> String
fileName (GeneratedFile -> String)
-> (GeneratedFile -> String) -> GeneratedFile -> (String, String)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& GeneratedFile -> String
fileContent
type = String -> String
execBackend :: MkFiles () -> IO [GeneratedFile]
execBackend :: MkFiles () -> IO [GeneratedFile]
execBackend = MkFiles () -> IO [GeneratedFile]
forall (m :: * -> *) w a. Monad m => WriterT w m a -> m w
execWriterT
mkfile :: FileContent c => FilePath -> MakeComment -> c -> MkFiles ()
mkfile :: String -> (String -> String) -> c -> MkFiles ()
mkfile String
path String -> String
f c
content = [GeneratedFile] -> MkFiles ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell [String -> (String -> String) -> String -> GeneratedFile
GeneratedFile String
path String -> String
f (c -> String
forall a. FileContent a => a -> String
fileContentToString c
content)]
class FileContent a where
fileContentToString :: a -> String
instance FileContent [Char] where
fileContentToString :: String -> String
fileContentToString = String -> String
deleteTrailingWhiteSpace
instance FileContent Doc where
fileContentToString :: Doc -> String
fileContentToString = String -> String
deleteTrailingWhiteSpace (String -> String) -> (Doc -> String) -> Doc -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc -> String
render
deleteTrailingWhiteSpace :: String -> String
deleteTrailingWhiteSpace :: String -> String
deleteTrailingWhiteSpace = [String] -> String
unlines ([String] -> String) -> (String -> [String]) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ((Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
List.dropWhileEnd Char -> Bool
isSpace) ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines
writeFiles :: FilePath -> MkFiles () -> IO ()
writeFiles :: String -> MkFiles () -> IO ()
writeFiles String
root MkFiles ()
fw = do
[GeneratedFile]
fb <- MkFiles () -> IO [GeneratedFile]
execBackend MkFiles ()
fw
Bool -> String -> IO ()
createDirectoryIfMissing Bool
True String
root
[GeneratedFile] -> (GeneratedFile -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [GeneratedFile]
fb ((GeneratedFile -> IO ()) -> IO ())
-> (GeneratedFile -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ (GeneratedFile String
path String -> String
mkComment String
content) -> do
Bool -> String -> IO ()
createDirectoryIfMissing Bool
True (String
root String -> String -> String
</> String -> String
dropFileName String
path)
String -> String -> IO ()
writeFileRep (String
root String -> String -> String
</> String
path) (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
if String -> String
takeExtension String
path String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
".txt" then
[String] -> String
unlines [ String
content, String -> String
mkComment String
msgGenerated ]
else
String -> String
mkComment String
msgGenerated String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\n\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
content