From b586838fb37d1ea5afa9cae2076f5e9b3ddb2c88 Mon Sep 17 00:00:00 2001
From: Pavel Kirilin <win10@list.ru>
Date: Sun, 14 Jun 2020 23:16:07 +0400
Subject: [PATCH] REPL is done. Description: - Added REPL functionality. -
 REFACTOR NEEDED!!! - Added test.bf

Signed-off-by: Pavel Kirilin <win10@list.ru>
---
 app/Main.hs        |   3 +-
 src/Definitions.hs |  12 +++-
 src/LangParser.hs  |  13 ++--
 src/Lib.hs         |  14 +----
 src/REPL.hs        | 146 +++++++++++++++++++++++++++++++++++++++++----
 test.bf            |   9 ++-
 6 files changed, 162 insertions(+), 35 deletions(-)

diff --git a/app/Main.hs b/app/Main.hs
index 3ff761e..0da7cc9 100644
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -1,12 +1,13 @@
 module Main where
 
 import           Lib
+import           REPL
 import           Options
 import           MainOptions
 import           System.Environment
 
 main :: IO ()
 main = runCommand $ \opts args -> case (input opts, output opts) of
-    (""    , ""     ) -> startRepl
+    (""    , ""     ) -> startREPL  
     (inFile, ""     ) -> runFile inFile
     (inFile, outFile) -> compileFile inFile outFile
diff --git a/src/Definitions.hs b/src/Definitions.hs
index 25b7c40..56cfcad 100644
--- a/src/Definitions.hs
+++ b/src/Definitions.hs
@@ -1,6 +1,7 @@
 module Definitions where
 
-data BrainBreakOperation = Increment
+data BrainBreakOperation = 
+    Increment
     | Decrement
     | MoveRight
     | MoveLeft
@@ -12,6 +13,11 @@ data BrainBreakOperation = Increment
 
 type BrainBreakBlock = [BrainBreakOperation]
 
-data REPLHelpers = PrintState  deriving (Show)
+data REPLHelpers = 
+    PrintState
+    | PrintBuf
+    | PrintBufChars  deriving (Show)
 
-data REPLCode = Code BrainBreakBlock | Helper REPLHelpers  deriving (Show)
+data REPLCode = 
+    Code BrainBreakBlock 
+    | Helper REPLHelpers  deriving (Show)
diff --git a/src/LangParser.hs b/src/LangParser.hs
index 6e191e1..aa3c0cc 100644
--- a/src/LangParser.hs
+++ b/src/LangParser.hs
@@ -43,11 +43,12 @@ parseBrainBreak =
     parseDecrement = symbolic '-' $> Decrement
 
 parseReplHelpers :: Parser REPLHelpers
-parseReplHelpers = parsePrintState
-    where parsePrintState = symbol ":state" $> PrintState
+parseReplHelpers = parsePrintState <|> parsePrintBufChars <|> parsePrintBuf
+  where
+    parsePrintBuf      = symbol ":buf"   $> PrintBuf
+    parsePrintState    = symbol ":state" $> PrintState
+    parsePrintBufChars = symbol ":bufc"  $> PrintBufChars
 
 parseREPLCode :: Parser REPLCode
-parseREPLCode = 
-    Helper <$> parseReplHelpers 
-    <|> Code <$> parseBrainBreak
-        
+parseREPLCode = Helper <$> parseReplHelpers <|> Code <$> parseBrainBreak
+
diff --git a/src/Lib.hs b/src/Lib.hs
index 978eebd..be98d25 100644
--- a/src/Lib.hs
+++ b/src/Lib.hs
@@ -1,27 +1,19 @@
 module Lib where
 
 import           REPL
+import           Data.List
 import           LangParser
 import           Definitions
 import           Text.Trifecta
-import           Data.List
+import           Control.Monad.State
 
-startRepl :: IO ()
-startRepl = do
-    input <- getLine
-    let parsed_string = parseString parseREPLCode mempty input
-    case parsed_string of
-        Success code -> runReplCode code
-        Failure info -> print (_errDoc info)
-    startRepl
 
 runFile :: String -> IO ()
 runFile filename = do
     parse_result <- parseFromFileEx parseBrainBreak filename
     case parse_result of
-        Success code -> print (filterComments code)
+        Success code -> evalStateT (runBrainBreakCode code) defaultState
         Failure info -> print (_errDoc info)
 
-
 compileFile :: String -> String -> IO ()
 compileFile input output = putStrLn "Compiling code developing is in progress."
diff --git a/src/REPL.hs b/src/REPL.hs
index 131fb5a..d863730 100644
--- a/src/REPL.hs
+++ b/src/REPL.hs
@@ -1,10 +1,14 @@
 module REPL where
 
-import           Control.Monad.State
+import           LangParser
 import           Definitions
+import           Text.Trifecta
+import           Control.Monad.State
+import           System.IO
 
 data REPLState = REPLState{
     buffer :: [Integer],
+    inputNumber :: Integer,
     index :: Integer,
     offset :: Integer
 } deriving (Show)
@@ -18,9 +22,27 @@ data Direction =
 replicaFactor :: Int
 replicaFactor = 3000
 
+io :: IO a -> StateT REPLState IO a
+io = liftIO
+
+prompt :: String -> IO String
+prompt text = do
+    putStr text
+    hFlush stdout
+    getLine
+
 defaultState :: REPLState
-defaultState =
-    REPLState { buffer = replicate replicaFactor 0, index = 0, offset = 0 }
+defaultState = REPLState { buffer      = replicate replicaFactor 0
+                         , inputNumber = 0
+                         , index       = 0
+                         , offset      = 0
+                         }
+
+updateListElement :: [Integer] -> Integer -> (Integer -> Integer) -> [Integer]
+updateListElement list index update = do
+    let element = update $ list !! fromInteger index
+    let (x,_:ys) = splitAt (fromInteger index) list
+    x ++ element : ys
 
 expandIfNeeded :: [Integer] -> Integer -> [Integer]
 -- Expand buffer to travel left but index is less than zero
@@ -32,31 +54,44 @@ expandIfNeeded old_buffer new_index = old_buffer
     needed len | len >= 0 = replicate replicaFactor 0
                | len < 0  = []
 
+increaseInputNumber :: REPLState -> REPLState
+increaseInputNumber state = state { inputNumber = inputNumber state + 1 }
+
 -- Fuction to update state accordingly to walk direction
 walkUpdate :: Direction -> REPLState -> REPLState
 -- Walk left with buffer expnding if needed
-walkUpdate LeftDirection old_state  = do
+walkUpdate LeftDirection old_state = do
     let update_func t = t - 1
     let updated_buffer =
             expandIfNeeded (buffer old_state) (update_func $ index old_state)
     -- Finding diff because we need to update current index correctly
     let len_diff =
             toInteger $ length updated_buffer - length (buffer old_state)
-    REPLState { buffer = updated_buffer
+    old_state { buffer = updated_buffer
               , index  = update_func $ index old_state + len_diff
               , offset = update_func $ offset old_state
               }
 
-walkUpdate RightDirection old_state  = do
+walkUpdate RightDirection old_state = do
     let update_func t = t + 1
     let updated_buffer =
             expandIfNeeded (buffer old_state) (update_func $ index old_state)
-    REPLState { buffer = updated_buffer
+    old_state { buffer = updated_buffer
               , index  = update_func $ index old_state
               , offset = update_func $ offset old_state
               }
 
-walk :: Direction -> State REPLState ()
+updateStateCell :: (Integer -> Integer) -> REPLState -> REPLState
+updateStateCell update_func old_state = do
+    let new_buffer = updateListElement (buffer old_state) (index old_state) update_func
+    old_state{
+        buffer = new_buffer
+    }
+
+updateCell :: (Integer->Integer) -> StateT REPLState IO ()
+updateCell update_func = modify (updateStateCell update_func)
+
+walk :: Direction -> StateT REPLState IO ()
 walk direction = do
     modify (walkUpdate direction)
     return ()
@@ -64,8 +99,95 @@ walk direction = do
 doAction :: REPLCode -> State REPLState ()
 doAction = undefined
 
-runHelper :: REPLHelpers -> State REPLState ()
-runHelper = undefined
 
-runReplCode :: REPLCode -> IO ()
-runReplCode = undefined
\ No newline at end of file
+getBufferSlice :: Integer -> Integer ->  [Integer] -> [Integer]
+getBufferSlice size current_index current_buffer = do
+    let start        = fromInteger $ current_index - size
+    let end          = fromInteger $ current_index + size
+    drop start $ take end current_buffer
+
+runHelper :: REPLHelpers -> StateT REPLState IO ()
+runHelper PrintState = do
+    current_state <- get
+    let buffer_slice = getBufferSlice 5 (index current_state) (buffer current_state)
+    io $ putStrLn $ "Current index: " ++ show (index current_state)
+    io $ putStrLn $ "Offset from start: " ++ show (offset current_state)
+    io $ putStrLn $ "part of curren buffer: \n" ++ show buffer_slice
+    return ()
+
+runHelper PrintBuf = do
+    current_state <- get
+    let buffer_slice = getBufferSlice 5 (index current_state) (buffer current_state)
+    io $ print buffer_slice
+    return ()
+
+runHelper PrintBufChars  = do
+    current_state <- get
+    let buffer_slice = getBufferSlice 5 (index current_state) (buffer current_state)
+    io $ print $ map (\t -> toEnum (fromInteger t) :: Char) buffer_slice
+    return ()
+
+getCell :: StateT REPLState IO Integer
+getCell = do
+    state <- get
+    return $ buffer state !! fromInteger (index state)
+
+printCell :: StateT REPLState IO ()
+printCell = do
+    cell <- getCell
+    io $ putChar (toEnum (fromInteger cell) :: Char)
+    io $ hFlush stdout
+    return ()
+
+readCell :: StateT REPLState IO ()
+readCell = do
+    char <- io getChar
+    updateCell (const $ toInteger $ fromEnum char)
+    return ()
+
+runBrainCodeLoop :: BrainBreakBlock -> StateT REPLState IO ()
+runBrainCodeLoop  code = do
+    runBrainBreakCode code
+    cell <- getCell
+    case cell of 
+        0 -> return ()
+        val -> runBrainCodeLoop code
+
+runBrainBreakOperation :: BrainBreakOperation -> StateT REPLState IO ()
+runBrainBreakOperation MoveLeft         = walk LeftDirection
+runBrainBreakOperation MoveRight        = walk RightDirection
+runBrainBreakOperation Increment        = updateCell (+1)
+runBrainBreakOperation Decrement        = updateCell (\t -> t - 1)
+runBrainBreakOperation Write            = printCell
+runBrainBreakOperation Read             = readCell
+runBrainBreakOperation (Loop code)      = runBrainCodeLoop code
+runBrainBreakOperation Comment          = return ()
+
+runBrainBreakCode :: BrainBreakBlock -> StateT REPLState IO ()
+runBrainBreakCode (x : xs) = do
+    runBrainBreakOperation x
+    runBrainBreakCode xs
+runBrainBreakCode [] = return ()
+
+
+replCodeRunner :: REPLCode -> StateT REPLState IO ()
+replCodeRunner code = case code of
+    Helper helper  -> runHelper helper
+    Code   bb_code -> runBrainBreakCode $ filterComments bb_code
+
+runREPL :: StateT REPLState IO ()
+runREPL = do
+    state <- get
+    io $ putStr $ "\nIn [" ++ show (inputNumber state) ++ "]: "
+    io $ hFlush stdout
+    input <- io getLine
+    let code = parseString parseREPLCode mempty input
+    case code of
+        Success code -> replCodeRunner code
+        Failure info -> io $ print (_errDoc info)
+    modify increaseInputNumber
+    runREPL
+
+
+startREPL :: IO ()
+startREPL = evalStateT runREPL defaultState
\ No newline at end of file
diff --git a/test.bf b/test.bf
index 609fbfe..7c7ddff 100644
--- a/test.bf
+++ b/test.bf
@@ -1,2 +1,7 @@
-This is test file to check how parser works;
-<++[-_-]++>
+++++++++++[
+    >+++++++>++++++++++>+++>+<<<<-
+    ]
+    >++.>+.+++++++..
+    +++.>++.<<+++++++++++++++.
+    >.+++
+.------.--------.>+.>.
\ No newline at end of file
-- 
GitLab