diff --git a/src/Interpreter.hs b/src/Interpreter.hs index 9309d75..3a06967 100644 --- a/src/Interpreter.hs +++ b/src/Interpreter.hs @@ -69,21 +69,26 @@ errorDesc LoopNoMatch = "ERROR: '[' or ']' not working. Matching parenthesis not incrIP :: State -> State incrIP p = p { ip = ip p + 1 } -execUpdate :: Instruction -> State -> Execution State -execUpdate i p = Working p { tape = newTape } +execUpdate :: Instruction -> State -> State +execUpdate i p = p { tape = newTape } where newTape = tapeHelp (tape p) (dp p) (updateCell i) execTapeLeft :: State -> Execution State execTapeLeft p = case dp p of 0 -> Crash NegTape n -> Working p { dp = n - 1 } -execTapeRight :: State -> Execution State -execTapeRight p = Working p { tape = tape p ++ newTape, dp = dp p + 1 } +execTapeRight :: State -> State +execTapeRight p = p { tape = tape p ++ newTape, dp = dp p + 1 } where newTape = case dp p == length (tape p) - 1 of True -> [Byte 0] _ -> [] -execOut :: State -> Execution State -execOut p = Working p { output = output p ++ [chr char]} +execIn :: State -> IO (Execution State) +execIn p = do chr <- getChar + tp <- pure $ fromEnum chr + return $ Working p { tape = tapeHelp (tape p) (dp p) (\_ -> Byte tp) } + +execOut :: State -> State +execOut p = p { output = output p ++ [chr char]} where char = tape p !! dp p findMatching :: Program -> Instruction -> Int -> Maybe Int @@ -110,19 +115,24 @@ execLoop d w = case posOrF of Just n -> Working w { ip = n } posOrF = case jump of True -> findMatching (program w) d (ip w) _ -> Just $ ip w -execute :: State -> Execution State -execute w = do ran <- (traceShowId $ runInstr w) - newStatus <- checkDone ran - execute newStatus - where instrFor w = case (program w !! ip w) of - TapeLeft -> execTapeLeft - TapeRight -> execTapeRight - Add -> execUpdate Add - Sub -> execUpdate Sub - Out -> execOut - l -> execLoop l +execute :: State -> IO (Execution State) +execute w = runInstr w >>= andThen + where instrFor :: State -> State -> IO (Execution State) + instrFor w = case (program w !! ip w) of + TapeLeft -> fmap return $ execTapeLeft + TapeRight -> return . return . execTapeRight + Add -> return . return . (execUpdate Add) + Sub -> return . return . (execUpdate Sub) + In -> execIn + Out -> return . return . execOut + l -> fmap return $ execLoop l - runInstr :: State -> Execution State + andThen :: Execution State -> IO (Execution State) + andThen s = case s >>= checkDone of + Working s -> execute s + t -> return t + + runInstr :: State -> IO (Execution State) runInstr w = instrFor w $ w checkDone :: State -> Execution State @@ -131,6 +141,7 @@ execute w = do ran <- (traceShowId $ runInstr w) | otherwise = Working $ ps { ip = newIP } where newIP = ip ps + 1 + initState :: Program -> State initState p = State { tape = [Byte 0], @@ -139,6 +150,6 @@ initState p = State { program = p, ip = 0} -run :: String -> Execution State -run "" = Done "" +run :: String -> IO (Execution State) +run "" = return $ Done "" run s = execute . initState . catMaybes . fmap parseInstr $ s