{-# Language GADTs #-}
{-# Language DataKinds #-}
module EVM.Stepper
  ( Action (..)
  , Stepper
  , exec
  , execFully
  , run
  , runFully
  , wait
  , ask
  , evm
  , entering
  , enter
  , interpret
  )
where
import Prelude hiding (fail)
import Control.Monad.Operational (Program, singleton, view, ProgramViewT(..), ProgramView)
import Control.Monad.State.Strict (runState, liftIO, StateT)
import qualified Control.Monad.State.Class as State
import qualified EVM.Exec
import Data.Text (Text)
import EVM.Types (Buffer)
import EVM (EVM, VM, VMResult (VMFailure, VMSuccess), Error (Query, Choose), Query, Choose)
import qualified EVM
import qualified EVM.Fetch as Fetch
data Action a where
  
  Exec ::           Action VMResult
  
  Run ::             Action VM
  
  Wait :: Query   -> Action ()
  
  Ask :: Choose -> Action ()
  
  EVM  :: EVM a   -> Action a
type Stepper a = Program Action a
exec :: Stepper VMResult
exec :: Stepper VMResult
exec = Action VMResult -> Stepper VMResult
forall (instr :: * -> *) a (m :: * -> *).
instr a -> ProgramT instr m a
singleton Action VMResult
Exec
run :: Stepper VM
run :: Stepper VM
run = Action VM -> Stepper VM
forall (instr :: * -> *) a (m :: * -> *).
instr a -> ProgramT instr m a
singleton Action VM
Run
wait :: Query -> Stepper ()
wait :: Query -> Stepper ()
wait = Action () -> Stepper ()
forall (instr :: * -> *) a (m :: * -> *).
instr a -> ProgramT instr m a
singleton (Action () -> Stepper ())
-> (Query -> Action ()) -> Query -> Stepper ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Query -> Action ()
Wait
ask :: Choose -> Stepper ()
ask :: Choose -> Stepper ()
ask = Action () -> Stepper ()
forall (instr :: * -> *) a (m :: * -> *).
instr a -> ProgramT instr m a
singleton (Action () -> Stepper ())
-> (Choose -> Action ()) -> Choose -> Stepper ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Choose -> Action ()
Ask
evm :: EVM a -> Stepper a
evm :: EVM a -> Stepper a
evm = Action a -> Stepper a
forall (instr :: * -> *) a (m :: * -> *).
instr a -> ProgramT instr m a
singleton (Action a -> Stepper a)
-> (EVM a -> Action a) -> EVM a -> Stepper a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EVM a -> Action a
forall a. EVM a -> Action a
EVM
execFully :: Stepper (Either Error Buffer)
execFully :: Stepper (Either Error Buffer)
execFully =
  Stepper VMResult
exec Stepper VMResult
-> (VMResult -> Stepper (Either Error Buffer))
-> Stepper (Either Error Buffer)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    VMFailure (Query q :: Query
q) ->
      Query -> Stepper ()
wait Query
q Stepper ()
-> Stepper (Either Error Buffer) -> Stepper (Either Error Buffer)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Stepper (Either Error Buffer)
execFully
    VMFailure (Choose q :: Choose
q) ->
      Choose -> Stepper ()
ask Choose
q Stepper ()
-> Stepper (Either Error Buffer) -> Stepper (Either Error Buffer)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Stepper (Either Error Buffer)
execFully
    VMFailure x :: Error
x ->
      Either Error Buffer -> Stepper (Either Error Buffer)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Error -> Either Error Buffer
forall a b. a -> Either a b
Left Error
x)
    VMSuccess x :: Buffer
x ->
      Either Error Buffer -> Stepper (Either Error Buffer)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Buffer -> Either Error Buffer
forall a b. b -> Either a b
Right Buffer
x)
runFully :: Stepper EVM.VM
runFully :: Stepper VM
runFully = do
  VM
vm <- Stepper VM
run
  case VM -> Maybe VMResult
EVM._result VM
vm of
    Nothing -> [Char] -> Stepper VM
forall a. HasCallStack => [Char] -> a
error "should not occur"
    Just (VMFailure (Query q :: Query
q)) ->
      Query -> Stepper ()
wait Query
q Stepper () -> Stepper VM -> Stepper VM
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Stepper VM
runFully
    Just (VMFailure (Choose q :: Choose
q)) ->
      Choose -> Stepper ()
ask Choose
q Stepper () -> Stepper VM -> Stepper VM
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Stepper VM
runFully
    Just _ ->
      VM -> Stepper VM
forall (f :: * -> *) a. Applicative f => a -> f a
pure VM
vm
entering :: Text -> Stepper a -> Stepper a
entering :: Text -> Stepper a -> Stepper a
entering t :: Text
t stepper :: Stepper a
stepper = do
  EVM () -> Stepper ()
forall a. EVM a -> Stepper a
evm (TraceData -> EVM ()
EVM.pushTrace (Text -> TraceData
EVM.EntryTrace Text
t))
  a
x <- Stepper a
stepper
  EVM () -> Stepper ()
forall a. EVM a -> Stepper a
evm EVM ()
EVM.popTrace
  a -> Stepper a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
x
enter :: Text -> Stepper ()
enter :: Text -> Stepper ()
enter t :: Text
t = EVM () -> Stepper ()
forall a. EVM a -> Stepper a
evm (TraceData -> EVM ()
EVM.pushTrace (Text -> TraceData
EVM.EntryTrace Text
t))
interpret :: Fetch.Fetcher -> Stepper a -> StateT VM IO a
interpret :: Fetcher -> Stepper a -> StateT VM IO a
interpret fetcher :: Fetcher
fetcher =
  ProgramView Action a -> StateT VM IO a
forall a. ProgramView Action a -> StateT VM IO a
eval (ProgramView Action a -> StateT VM IO a)
-> (Stepper a -> ProgramView Action a)
-> Stepper a
-> StateT VM IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Stepper a -> ProgramView Action a
forall (instr :: * -> *) a. Program instr a -> ProgramView instr a
view
  where
    eval
      :: ProgramView Action a
      -> StateT VM IO a
    eval :: ProgramView Action a -> StateT VM IO a
eval (Return x :: a
x) =
      a -> StateT VM IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
x
    eval (action :: Action b
action :>>= k :: b -> ProgramT Action Identity a
k) =
      case Action b
action of
        Exec ->
          StateT VM IO VMResult
forall (m :: * -> *). MonadState VM m => m VMResult
EVM.Exec.exec StateT VM IO VMResult
-> (VMResult -> StateT VM IO a) -> StateT VM IO a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Fetcher -> ProgramT Action Identity a -> StateT VM IO a
forall a. Fetcher -> Stepper a -> StateT VM IO a
interpret Fetcher
fetcher (ProgramT Action Identity a -> StateT VM IO a)
-> (b -> ProgramT Action Identity a) -> b -> StateT VM IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> ProgramT Action Identity a
k
        Run ->
          StateT VM IO VM
forall (m :: * -> *). MonadState VM m => m VM
EVM.Exec.run StateT VM IO VM -> (VM -> StateT VM IO a) -> StateT VM IO a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Fetcher -> ProgramT Action Identity a -> StateT VM IO a
forall a. Fetcher -> Stepper a -> StateT VM IO a
interpret Fetcher
fetcher (ProgramT Action Identity a -> StateT VM IO a)
-> (b -> ProgramT Action Identity a) -> b -> StateT VM IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> ProgramT Action Identity a
k
        Wait q :: Query
q ->
          do EVM ()
m <- IO (EVM ()) -> StateT VM IO (EVM ())
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (Fetcher
fetcher Query
q)
             (VM -> ((), VM)) -> StateT VM IO ()
forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
State.state (EVM () -> VM -> ((), VM)
forall s a. State s a -> s -> (a, s)
runState EVM ()
m) StateT VM IO () -> StateT VM IO a -> StateT VM IO a
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Fetcher -> ProgramT Action Identity a -> StateT VM IO a
forall a. Fetcher -> Stepper a -> StateT VM IO a
interpret Fetcher
fetcher (b -> ProgramT Action Identity a
k ())
        Ask _ ->
          [Char] -> StateT VM IO a
forall a. HasCallStack => [Char] -> a
error "cannot make choices with this interpreter"
        EVM m :: EVM b
m -> do
          b
r <- (VM -> (b, VM)) -> StateT VM IO b
forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
State.state (EVM b -> VM -> (b, VM)
forall s a. State s a -> s -> (a, s)
runState EVM b
m)
          Fetcher -> ProgramT Action Identity a -> StateT VM IO a
forall a. Fetcher -> Stepper a -> StateT VM IO a
interpret Fetcher
fetcher (b -> ProgramT Action Identity a
k b
r)