{-# LANGUAGE LambdaCase #-}

-- |
-- Module      : Jikka.Subcommand.Execute
-- Description : is the entry point of @execute@ subcommand. / @execute@ サブコマンドのエントリポイントです。
-- Copyright   : (c) Kimiyuki Onaka, 2021
-- License     : Apache License 2.0
-- Maintainer  : kimiyuki95@gmail.com
-- Stability   : experimental
-- Portability : portable
module Jikka.Main.Subcommand.Execute (run) where

import Control.Monad.Except
import qualified Data.Text.IO as T (readFile)
import Jikka.Common.Alpha
import Jikka.Common.Error
import qualified Jikka.Core.Convert as ConvertCore
import qualified Jikka.Core.Evaluate as EvaluateCore
import qualified Jikka.Core.Language.Value as ValueCore
import Jikka.Main.Target
import qualified Jikka.Python.Convert.ToRestrictedPython as ToRestrictedPython
import qualified Jikka.Python.Parse as FromPython
import qualified Jikka.RestrictedPython.Convert as ToCore
import qualified Jikka.RestrictedPython.Evaluate as EvaluateRestrictedPython
import qualified Jikka.RestrictedPython.Language.Value as ValueRestrictedPythong

runPython :: FilePath -> ExceptT Error IO ()
runPython :: FilePath -> ExceptT Error IO ()
runPython FilePath
_ = FilePath -> ExceptT Error IO ()
forall (m :: * -> *) a. MonadError Error m => FilePath -> m a
throwCommandLineError FilePath
"cannot execute Python"

runRestrictedPython :: FilePath -> ExceptT Error IO ()
runRestrictedPython :: FilePath -> ExceptT Error IO ()
runRestrictedPython FilePath
path = (AlphaT (ExceptT Error IO) () -> Int -> ExceptT Error IO ())
-> Int -> AlphaT (ExceptT Error IO) () -> ExceptT Error IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip AlphaT (ExceptT Error IO) () -> Int -> ExceptT Error IO ()
forall (m :: * -> *) a. Functor m => AlphaT m a -> Int -> m a
evalAlphaT Int
0 (AlphaT (ExceptT Error IO) () -> ExceptT Error IO ())
-> AlphaT (ExceptT Error IO) () -> ExceptT Error IO ()
forall a b. (a -> b) -> a -> b
$ do
  Text
prog <- IO Text -> AlphaT (ExceptT Error IO) Text
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Text -> AlphaT (ExceptT Error IO) Text)
-> IO Text -> AlphaT (ExceptT Error IO) Text
forall a b. (a -> b) -> a -> b
$ FilePath -> IO Text
T.readFile FilePath
path
  Program
prog <- Either Error Program -> AlphaT (ExceptT Error IO) Program
forall e (m :: * -> *) a. MonadError e m => Either e a -> m a
liftEither (Either Error Program -> AlphaT (ExceptT Error IO) Program)
-> Either Error Program -> AlphaT (ExceptT Error IO) Program
forall a b. (a -> b) -> a -> b
$ FilePath -> Text -> Either Error Program
forall (m :: * -> *).
MonadError Error m =>
FilePath -> Text -> m Program
FromPython.run FilePath
path Text
prog
  Program
prog <- Program -> AlphaT (ExceptT Error IO) Program
forall (m :: * -> *).
(MonadAlpha m, MonadError Error m) =>
Program -> m Program
ToRestrictedPython.run Program
prog
  (Program
prog, IOFormat
format) <- Program -> AlphaT (ExceptT Error IO) (Program, IOFormat)
forall (m :: * -> *).
(MonadAlpha m, MonadError Error m) =>
Program -> m (Program, IOFormat)
ToCore.run' Program
prog
  ([Value]
args, Map FilePath Value
env) <- IOFormat -> AlphaT (ExceptT Error IO) ([Value], Map FilePath Value)
forall (m :: * -> *).
(MonadIO m, MonadError Error m) =>
IOFormat -> m ([Value], Map FilePath Value)
ValueRestrictedPythong.readValueIO IOFormat
format
  Value
result <- Program -> [Value] -> AlphaT (ExceptT Error IO) Value
forall (m :: * -> *).
MonadError Error m =>
Program -> [Value] -> m Value
EvaluateRestrictedPython.run Program
prog [Value]
args
  IOFormat
-> Map FilePath Value -> Value -> AlphaT (ExceptT Error IO) ()
forall (m :: * -> *).
(MonadError Error m, MonadIO m) =>
IOFormat -> Map FilePath Value -> Value -> m ()
ValueRestrictedPythong.writeValueIO IOFormat
format Map FilePath Value
env Value
result

runCore :: FilePath -> ExceptT Error IO ()
runCore :: FilePath -> ExceptT Error IO ()
runCore FilePath
path = (AlphaT (ExceptT Error IO) () -> Int -> ExceptT Error IO ())
-> Int -> AlphaT (ExceptT Error IO) () -> ExceptT Error IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip AlphaT (ExceptT Error IO) () -> Int -> ExceptT Error IO ()
forall (m :: * -> *) a. Functor m => AlphaT m a -> Int -> m a
evalAlphaT Int
0 (AlphaT (ExceptT Error IO) () -> ExceptT Error IO ())
-> AlphaT (ExceptT Error IO) () -> ExceptT Error IO ()
forall a b. (a -> b) -> a -> b
$ do
  Text
prog <- IO Text -> AlphaT (ExceptT Error IO) Text
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Text -> AlphaT (ExceptT Error IO) Text)
-> IO Text -> AlphaT (ExceptT Error IO) Text
forall a b. (a -> b) -> a -> b
$ FilePath -> IO Text
T.readFile FilePath
path
  Program
prog <- Either Error Program -> AlphaT (ExceptT Error IO) Program
forall e (m :: * -> *) a. MonadError e m => Either e a -> m a
liftEither (Either Error Program -> AlphaT (ExceptT Error IO) Program)
-> Either Error Program -> AlphaT (ExceptT Error IO) Program
forall a b. (a -> b) -> a -> b
$ FilePath -> Text -> Either Error Program
forall (m :: * -> *).
MonadError Error m =>
FilePath -> Text -> m Program
FromPython.run FilePath
path Text
prog
  Program
prog <- Program -> AlphaT (ExceptT Error IO) Program
forall (m :: * -> *).
(MonadAlpha m, MonadError Error m) =>
Program -> m Program
ToRestrictedPython.run Program
prog
  (Program
prog, IOFormat
format) <- Program -> AlphaT (ExceptT Error IO) (Program, IOFormat)
forall (m :: * -> *).
(MonadAlpha m, MonadError Error m) =>
Program -> m (Program, IOFormat)
ToCore.run Program
prog
  Program
prog <- Program -> AlphaT (ExceptT Error IO) Program
forall (m :: * -> *).
(MonadAlpha m, MonadError Error m) =>
Program -> m Program
ConvertCore.run Program
prog
  ([Value]
args, Map FilePath Value
env) <- IOFormat -> AlphaT (ExceptT Error IO) ([Value], Map FilePath Value)
forall (m :: * -> *).
(MonadError Error m, MonadIO m) =>
IOFormat -> m ([Value], Map FilePath Value)
ValueCore.readValueIO IOFormat
format
  Value
result <- Program -> [Value] -> AlphaT (ExceptT Error IO) Value
forall (m :: * -> *).
(MonadAlpha m, MonadFix m, MonadError Error m) =>
Program -> [Value] -> m Value
EvaluateCore.run Program
prog [Value]
args
  IOFormat
-> Map FilePath Value -> Value -> AlphaT (ExceptT Error IO) ()
forall (m :: * -> *).
(MonadError Error m, MonadIO m) =>
IOFormat -> Map FilePath Value -> Value -> m ()
ValueCore.writeValueIO IOFormat
format Map FilePath Value
env Value
result

runCPlusPlus :: FilePath -> ExceptT Error IO ()
runCPlusPlus :: FilePath -> ExceptT Error IO ()
runCPlusPlus FilePath
_ = FilePath -> ExceptT Error IO ()
forall (m :: * -> *) a. MonadError Error m => FilePath -> m a
throwCommandLineError FilePath
"cannot execute C++"

run :: Target -> FilePath -> ExceptT Error IO ()
run :: Target -> FilePath -> ExceptT Error IO ()
run = \case
  Target
PythonTarget -> FilePath -> ExceptT Error IO ()
runPython
  Target
RestrictedPythonTarget -> FilePath -> ExceptT Error IO ()
runRestrictedPython
  Target
CoreTarget -> FilePath -> ExceptT Error IO ()
runCore
  Target
CPlusPlusTarget -> FilePath -> ExceptT Error IO ()
runCPlusPlus