{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-} -- | -- Module : Jikka.Subcommand.Convert -- Description : is the entry point of @convert@ subcommand. / @convert@ サブコマンドのエントリポイントです。 -- Copyright : (c) Kimiyuki Onaka, 2021 -- License : Apache License 2.0 -- Maintainer : kimiyuki95@gmail.com -- Stability : experimental -- Portability : portable module Jikka.Main.Subcommand.Convert (run) where import Data.Text (Text, pack) import qualified Jikka.CPlusPlus.Convert as FromCore import qualified Jikka.CPlusPlus.Convert.BurnFlavouredNames as BurnFlavouredNamesCPlusPlus import qualified Jikka.CPlusPlus.Format as FormatCPlusPlus import qualified Jikka.CPlusPlus.Language.Expr as CPlusPlus import Jikka.Common.Alpha import Jikka.Common.Error import qualified Jikka.Core.Convert as Convert import qualified Jikka.Core.Format as FormatCore import qualified Jikka.Core.Language.Expr as Core import qualified Jikka.Core.Parse as ParseCore import Jikka.Main.Target import qualified Jikka.Python.Convert.ToRestrictedPython as ToRestrictedPython import qualified Jikka.Python.Language.Expr as Python import qualified Jikka.Python.Parse as ParsePython import qualified Jikka.RestrictedPython.Convert as ToCore import qualified Jikka.RestrictedPython.Format as FormatRestrictedPython import qualified Jikka.RestrictedPython.Language.Expr as RestrictedPython data Program = PythonProgram Python.Program | RestrictedPythonProgram RestrictedPython.Program | CoreProgram Core.Program | CPlusPlusProgram CPlusPlus.Program deriving (Eq, Ord, Read, Show) parseProgram :: (MonadAlpha m, MonadError Error m) => Target -> FilePath -> Text -> m Program parseProgram source path input = case source of PythonTarget -> PythonProgram <$> ParsePython.run path input RestrictedPythonTarget -> throwCommandLineError "cannot convert from restricted Python" CoreTarget -> CoreProgram <$> ParseCore.run path input CPlusPlusTarget -> throwCommandLineError "cannot convert from C++" convertProgram :: (MonadAlpha m, MonadError Error m) => Program -> Target -> m Program convertProgram prog target = case (prog, target) of (PythonProgram _, PythonTarget) -> return prog (RestrictedPythonProgram _, RestrictedPythonTarget) -> return prog (CoreProgram prog, CoreTarget) -> CoreProgram <$> Convert.run prog -- optimize (CPlusPlusProgram _, CPlusPlusTarget) -> return prog (RestrictedPythonProgram _, PythonTarget) -> throwCommandLineError "cannot convert from restricted Python to Python" (CoreProgram _, PythonTarget) -> throwCommandLineError "cannot convert from core to Python" (CoreProgram _, RestrictedPythonTarget) -> throwCommandLineError "cannot convert from core to restricted Python" (PythonProgram prog, _) -> do prog <- ToRestrictedPython.run prog convertProgram (RestrictedPythonProgram prog) target (RestrictedPythonProgram prog, CoreTarget) -> do (prog, _) <- ToCore.run prog CoreProgram <$> Convert.run prog (RestrictedPythonProgram prog, CPlusPlusTarget) -> do (prog, format) <- ToCore.run prog prog <- Convert.run prog CPlusPlusProgram <$> FromCore.run prog (Just format) (CoreProgram prog, CPlusPlusTarget) -> do prog <- Convert.run prog CPlusPlusProgram <$> FromCore.run prog Nothing (CPlusPlusProgram _, _) -> throwCommandLineError "cannot convert from C++" formatProgram :: (MonadAlpha m, MonadError Error m) => Program -> m Text formatProgram = \case PythonProgram prog -> return . pack $ show prog -- TODO RestrictedPythonProgram prog -> FormatRestrictedPython.run prog CoreProgram prog -> FormatCore.run prog CPlusPlusProgram prog -> do prog <- BurnFlavouredNamesCPlusPlus.run prog FormatCPlusPlus.run prog run :: Target -> Target -> FilePath -> Text -> Either Error Text run source target path input = flip evalAlphaT 0 $ do prog <- parseProgram source path input prog <- convertProgram prog target formatProgram prog