module Language.Fiddle.Compiler.Backend where import Control.Monad (forM_) import Control.Monad.Identity (Identity) import Control.Monad.Writer import Data.Map (Map) import qualified Data.Text.IO import qualified Data.Map as Map import Data.Text (Text) import Language.Fiddle.Ast import Language.Fiddle.Types (Commented, SourceSpan) import Options.Applicative -- | Data representing the result of transpilation. data TranspileResult where TranspileResult :: { newFileContents :: Map FilePath Text } -> TranspileResult instance Semigroup TranspileResult where (<>) (TranspileResult c1) (TranspileResult c2) = TranspileResult $ Map.unionWith (<>) c1 c2 instance Monoid TranspileResult where mempty = TranspileResult mempty -- | A backend for the FiddleCompiler. Takes a Checked FiddleUnit and emits -- generated code for that fiddle unit. data Backend where Backend :: forall privateFlags privateState. { backendName :: String, backendOptionsParser :: Parser privateFlags, backendIOMakeState :: privateFlags -> IO privateState, backendTranspile :: privateFlags -> privateState -> FiddleUnit Checked Identity (Commented SourceSpan) -> TranspileResult } -> Backend backendToParserFunction :: Backend -> Parser ( FiddleUnit Checked Identity (Commented SourceSpan) -> IO TranspileResult ) backendToParserFunction Backend { backendOptionsParser = optionsParser, backendIOMakeState = ioMakeState, backendTranspile = transpile } = ( \opts -> let ioState = ioMakeState opts in \fiddleUnit -> do state <- ioState return $ transpile opts state fiddleUnit ) <$> optionsParser processTranspileResult :: TranspileResult -> IO () processTranspileResult (TranspileResult mp) = forM_ (Map.toList mp) $ \(file, text) -> do Data.Text.IO.writeFile file text nullBackend :: Backend nullBackend = Backend { backendName = "null", backendOptionsParser = pure (), backendIOMakeState = const $ return (), backendTranspile = \_ _ _ -> mempty }