summaryrefslogtreecommitdiff
path: root/interpreter.hs
blob: 59b9402a09e8249014b7ccc566b6cc66b4921200 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{-# LANGUAGE BangPatterns #-}

module Interpreter(interpret) where

import qualified Data.Vector.Mutable as MV

import AST


type Tape = MV.IOVector Byte


interpret :: Program -> [Byte] -> IO [Byte]
interpret (Program inss) inp = MV.replicate 60000 0 >>= \tape -> interInss 0 tape 30000 inss inp

interInss :: Int -> Tape -> Int -> [Instruction] -> [Byte] -> IO [Byte]
interInss _ _ _ [] _ = return []
-- interInss count _ _ _ _ | count > 2000000000 = return []
interInss !count !tape !memp allinss@(ins:rest) inp = case ins of
    (IAdd value offset) -> do
        MV.modify tape (+ value) (memp + offset)
        interInss (count + 1) tape memp rest inp
    (ISet value offset) -> do
        MV.write tape (memp + offset) value
        interInss (count + 1) tape memp rest inp
    (IMove from tos) -> do
        value <- MV.read tape (memp + from)
        MV.write tape (memp + from) 0
        mapM_ (\(offset, multiplier) -> MV.modify tape ((+) (multiplier * value)) (memp + offset)) tos
        interInss (count + 1) tape memp rest inp
    (ISlide offset) -> do
        interInss (count + 1) tape (memp + offset) rest inp
    (ILoop iins offset) -> do
        value <- MV.read tape (memp + offset)
        if value /= 0
            then interInss (count + 1) tape memp (iins ++ allinss) inp
            else interInss (count + 1) tape memp rest inp
    (IInput offset) -> do
        let (c:cs) = inp
        MV.write tape (memp + offset) c
        interInss (count + 1) tape memp rest cs
    (IOutput offset) -> do
        value <- MV.read tape (memp + offset)
        (value :) <$> interInss (count + 1) tape memp rest inp
    IStart -> do
        interInss (count + 1) tape memp rest inp