Bytecode interpreter

Run Settings
LanguageHaskell
Language Version
Run Command
{-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE OverloadedLists #-} module Main ( main ) where import Control.Monad.ST (ST, runST) import Data.Bits ((.|.), shiftL) import Data.ByteString (ByteString) import Data.Function ((&)) import Data.Semigroup ((<>)) import Data.Vector.Mutable (MVector) import Data.Word (Word16) import qualified Data.ByteString as ByteString import qualified Data.Vector as Vector import qualified Data.Vector.Mutable as MVector data Value = BoolValue !Bool | IntValue {-# UNPACK #-} !Int deriving stock (Show) interpret :: ByteString -> Int -> MVector s Value -> ST s Value interpret code pc mem = case ByteString.index code pc of -- CONTINUE 0x00 -> interpret code (pc + 1) mem -- GOTO 0x01 -> do let target = decodeWord16 code (pc + 1) & fromIntegral interpret code target mem -- IF 0x02 -> do let target = decodeWord16 code (pc + 1) & fromIntegral let reg = decodeWord16 code (pc + 3) & fromIntegral BoolValue condition <- MVector.read mem reg if condition then interpret code target mem else interpret code (pc + 5) mem -- RETURN 0x04 -> do let reg = decodeWord16 code (pc + 1) & fromIntegral MVector.read mem reg -- COPY 0x10 -> do let sourceReg = decodeWord16 code (pc + 1) & fromIntegral let targetReg = decodeWord16 code (pc + 3) & fromIntegral value <- MVector.read mem sourceReg MVector.write mem targetReg value interpret code (pc + 5) mem other -> fail $ "Invalid opcode: " <> show other decodeWord16 :: ByteString -> Int -> Word16 decodeWord16 bs i = let b1 = fromIntegral $ ByteString.index bs (i + 0) in let b2 = fromIntegral $ ByteString.index bs (i + 1) in b2 `shiftL` 8 .|. b1 {-# INLINE decodeWord16 #-} main :: IO () main = let code = ByteString.pack [ {- 0 -} 0x00 -- CONTINUE , {- 1 -} 0x01, 0x05, 0x00 -- GOTO 5 , {- 4 -} 0xFF -- (invalid opcode) , {- 5 -} 0x02, 0x0F, 0x00 -- IF 15 0 , 0x00, 0x00 , {- 10 -} 0x10, 0x02, 0x00 -- COPY 2 3 , 0x03, 0x00 , {- 15 -} 0x02, 0x17, 0x00 -- IF 23 1 , 0x01, 0x00 , {- 20 -} 0x04, 0x02, 0x00 -- RETURN 2 , {- 23 -} 0x04, 0x03, 0x00 -- RETURN 3 ] pc = 0 mem1 = Vector.thaw [BoolValue True, BoolValue True, IntValue 1, IntValue 2] mem2 = Vector.thaw [BoolValue True, BoolValue False, IntValue 1, IntValue 2] mem3 = Vector.thaw [BoolValue False, BoolValue True, IntValue 1, IntValue 2] mem4 = Vector.thaw [BoolValue False, BoolValue False, IntValue 1, IntValue 2] in do { print $ runST (interpret code pc =<< mem1) ; print $ runST (interpret code pc =<< mem2) ; print $ runST (interpret code pc =<< mem3) ; print $ runST (interpret code pc =<< mem4) }
Editor Settings
Theme
Key bindings
Full width
Lines