module VM.Instruction.System
( instPrint
, instHalt
, instExit
, instCheckStack
) where
import System.Exit (exitWith, ExitCode(..))
import Control.Monad.State.Strict (liftIO, modify, get)
import qualified Data.Vector as V
import qualified Data.Text.IO as TIO
import VM.VMState (VirtualMachine, VMState(..))
import VM.VMValue (valueToString, valueToInt)
import VM.VMStack (stackPop)
import VM.Bytecode.Reader (readInt32)
instPrint :: VirtualMachine ()
instPrint :: VirtualMachine ()
instPrint = do
val <- VirtualMachine VMValue
stackPop
liftIO $ TIO.putStr (valueToString val)
instHalt :: VirtualMachine ()
instHalt :: VirtualMachine ()
instHalt = (VMState -> VMState) -> VirtualMachine ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((VMState -> VMState) -> VirtualMachine ())
-> (VMState -> VMState) -> VirtualMachine ()
forall a b. (a -> b) -> a -> b
$ \VMState
vm -> VMState
vm { isRunning = False }
instCheckStack :: VirtualMachine ()
instCheckStack :: VirtualMachine ()
instCheckStack = do
required <- VirtualMachine Int
readInt32
vm <- get
case V.length (vStack vm) >= required of
Bool
False -> [Char] -> VirtualMachine ()
forall a. HasCallStack => [Char] -> a
error ([Char] -> VirtualMachine ()) -> [Char] -> VirtualMachine ()
forall a b. (a -> b) -> a -> b
$ [Char]
"VM Error: Stack Check Failed (Required: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
Int -> [Char]
forall a. Show a => a -> [Char]
show Int
required [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
", Actual: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show (Vector VMValue -> Int
forall a. Vector a -> Int
V.length (VMState -> Vector VMValue
vStack VMState
vm)) [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
")"
Bool
True -> () -> VirtualMachine ()
forall a. a -> StateT VMState IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
instExit :: VirtualMachine ()
instExit :: VirtualMachine ()
instExit = do
v <- VirtualMachine VMValue
stackPop
let code = VMValue -> Int
valueToInt VMValue
v
case code of
Int
0 -> IO () -> VirtualMachine ()
forall a. IO a -> StateT VMState IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> VirtualMachine ()) -> IO () -> VirtualMachine ()
forall a b. (a -> b) -> a -> b
$ ExitCode -> IO ()
forall a. ExitCode -> IO a
exitWith ExitCode
ExitSuccess
Int
_ -> IO () -> VirtualMachine ()
forall a. IO a -> StateT VMState IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> VirtualMachine ()) -> IO () -> VirtualMachine ()
forall a b. (a -> b) -> a -> b
$ ExitCode -> IO ()
forall a. ExitCode -> IO a
exitWith (Int -> ExitCode
ExitFailure Int
code)