diff options
| author | Jan Tuomi <jans.tuomi@gmail.com> | 2022-01-30 21:23:47 +0200 |
|---|---|---|
| committer | Jan Tuomi <jans.tuomi@gmail.com> | 2022-01-30 21:38:29 +0200 |
| commit | dd46dafe65e93b687ce5051288ab3f5cbfb7e09a (patch) | |
| tree | d527397c5f2205f6b6754f96fdd7166cc87a92e0 /src/interpreter.hs | |
| parent | 542b0d035444416cae8994f89d1ae11c4e4c5df9 (diff) | |
Monadic error handling
Diffstat (limited to 'src/interpreter.hs')
| -rw-r--r-- | src/interpreter.hs | 122 |
1 files changed, 68 insertions, 54 deletions
diff --git a/src/interpreter.hs b/src/interpreter.hs index 6eb6697..01cc474 100644 --- a/src/interpreter.hs +++ b/src/interpreter.hs @@ -1,5 +1,6 @@ module Interpreter where +import Control.Monad.Except import Data.Char import Data.Map (Map, (!)) import qualified Data.Map as M @@ -19,21 +20,21 @@ debugWaitForChar Config {configDebugMode = mode} = debugPrint Config {configDebugMode = mode} message = if mode - then putStrLn $ "[debug] " ++ message + then liftIO $ putStrLn $ "[debug] " ++ message else pure () -interpretSource :: Config -> LState -> IO () +interpretSource :: Config -> LState -> ExceptT LException IO () interpretSource config LState {lSource = []} = pure () interpretSource config state@LState {lSource = (word : rest)} = do newState <- interpretWord state {lSource = rest} word - debugPrint config $ "processed " ++ show word ++ ", newState =" - debugState config newState - step <- debugWaitForChar config + liftIO $ debugPrint config $ "processed " ++ show word ++ ", newState =" + liftIO $ debugState config newState + step <- liftIO $ debugWaitForChar config case step of ExecContinue -> interpretSource config newState ExecExit -> pure () -interpretWord :: LState -> LWord -> IO LState +interpretWord :: LState -> LWord -> ExceptT LException IO LState -- non-nestable structures interpretWord state@LState {lStack = stack, lPhraseDepth = phraseDepth} word@(LSymbol "define") = pure $ @@ -106,51 +107,51 @@ interpretWord state@LState {lDefs = defs, lDict = dict, lSource = source, lPhras in pure $ state {lStack = stack', lDict = newDict} "." -> do let (a : stack') = stack - putStrLn $ reprWord a + liftIO . putStrLn $ reprWord a pure $ state {lStack = stack'} "s." -> do let (word@(LPhrase ws) : stack') = stack let isLChar w = case w of LChar _ -> True; _ -> False - if not (all isLChar ws) - then error $ "[error] cannot string-print heterogenous phrase: " ++ reprWord word - else pure () + unless (all isLChar ws) $ throwError $ LException $ "cannot string-print heterogenous phrase: " ++ reprWord word let stringRepr = ws $> map (\(LChar c) -> c) - putStrLn stringRepr + liftIO . putStrLn $ stringRepr pure $ state {lStack = stack'} "?" -> do let (LLabel a : stack') = stack let lookupWord = dict ! a - putStrLn $ reprWord lookupWord + liftIO . putStrLn $ reprWord lookupWord pure $ state {lStack = stack'} - "+" -> + "+" -> do let (a : b : stack') = stack - result = lAddNumbers b a - in pure $ state {lStack = result : stack'} - "-" -> + result <- lAddNumbers b a + pure $ state {lStack = result : stack'} + "-" -> do let (a : b : stack') = stack - result = lSubNumbers b a - in pure $ state {lStack = result : stack'} - "*" -> + result <- lSubNumbers b a + pure $ state {lStack = result : stack'} + "*" -> do let (a : b : stack') = stack - result = lMultiplyNumbers b a - in pure $ state {lStack = result : stack'} - "/" -> + result <- lMultiplyNumbers b a + pure $ state {lStack = result : stack'} + "/" -> do let (a : b : stack') = stack - result = lDivideNumbers b a - in pure $ state {lStack = result : stack'} - "mod" -> + result <- lDivideNumbers b a + pure $ state {lStack = result : stack'} + "mod" -> do let (a : b : stack') = stack - result = lModNumbers b a - in pure $ state {lStack = result : stack'} - "eq?" -> + result <- lModNumbers b a + pure $ state {lStack = result : stack'} + "eq?" -> do let (a : b : stack') = stack - in pure $ state {lStack = LBool (a == b) : stack'} - "gt?" -> + pure $ state {lStack = LBool (a == b) : stack'} + "gt?" -> do let (a : b : stack') = stack - in pure $ state {lStack = lGreaterThan b a : stack'} - "lt?" -> + result <- lGreaterThan b a + pure $ state {lStack = result : stack'} + "lt?" -> do let (a : b : stack') = stack - in pure $ state {lStack = lLesserThan b a : stack'} + result <- lLesserThan b a + pure $ state {lStack = result : stack'} "unphrase" -> let (LPhrase phrase : stack') = stack in pure $ state {lSource = phrase ++ source, lStack = stack'} @@ -183,32 +184,45 @@ interpretWord state@LState {lDefs = defs, lDict = dict, lSource = source, lPhras ifWords = cond ++ [LPhrase (body ++ [condP, bodyP, LSymbol "loop"])] ++ [LPhrase [], LSymbol "cond"] newSource = ifWords ++ source in pure $ state {lStack = stack', lSource = newSource} - _ -> error $ "[error] not defined: " ++ symbol + _ -> throwError $ LException $ "not defined: " ++ symbol | otherwise = pure $ state {lStack = word : stack} -lAddNumbers (LInteger a) (LInteger b) = LInteger (a + b) -lAddNumbers (LFloat a) (LFloat b) = LFloat (a + b) -lAddNumbers a b = error $ "[error] sum is not defined for " ++ show a ++ ", " ++ show b +lAddNumbers :: LWord -> LWord -> ExceptT LException IO LWord +lAddNumbers (LInteger a) (LInteger b) = pure $ LInteger (a + b) +lAddNumbers (LFloat a) (LFloat b) = pure $ LFloat (a + b) +lAddNumbers a b = throwError $ LException $ "sum is not defined for " ++ show a ++ ", " ++ show b -lSubNumbers (LInteger a) (LInteger b) = LInteger (a - b) -lSubNumbers (LFloat a) (LFloat b) = LFloat (a - b) -lSubNumbers a b = error $ "[error] difference is not defined for " ++ show a ++ ", " ++ show b +lSubNumbers :: LWord -> LWord -> ExceptT LException IO LWord +lSubNumbers (LInteger a) (LInteger b) = pure $ LInteger (a - b) +lSubNumbers (LFloat a) (LFloat b) = pure $ LFloat (a - b) +lSubNumbers a b = throwError $ LException $ "difference is not defined for " ++ show a ++ ", " ++ show b -lMultiplyNumbers (LInteger a) (LInteger b) = LInteger (a * b) -lMultiplyNumbers (LFloat a) (LFloat b) = LFloat (a * b) -lMultiplyNumbers a b = error $ "[error] product is not defined for " ++ show a ++ ", " ++ show b +lMultiplyNumbers :: LWord -> LWord -> ExceptT LException IO LWord +lMultiplyNumbers (LInteger a) (LInteger b) = pure $ LInteger (a * b) +lMultiplyNumbers (LFloat a) (LFloat b) = pure $ LFloat (a * b) +lMultiplyNumbers a b = throwError $ LException $ "product is not defined for " ++ show a ++ ", " ++ show b -lDivideNumbers (LInteger a) (LInteger b) = LInteger (a `div` b) -lDivideNumbers (LFloat a) (LFloat b) = LFloat (a / b) -lDivideNumbers a b = error $ "[error] product is not defined for " ++ show a ++ ", " ++ show b +lDivideNumbers :: LWord -> LWord -> ExceptT LException IO LWord +lDivideNumbers (LInteger a) (LInteger b) = + case b of + 0 -> throwError $ LException "division by zero" + _ -> pure $ LInteger (a `div` b) +lDivideNumbers (LFloat a) (LFloat b) = + case b of + 0 -> throwError $ LException "division by zero" + _ -> pure $ LFloat (a / b) +lDivideNumbers a b = throwError $ LException $ "division is not defined for " ++ show a ++ ", " ++ show b -lGreaterThan (LInteger a) (LInteger b) = LBool (a > b) -lGreaterThan (LFloat a) (LFloat b) = LBool (a > b) -lGreaterThan a b = error $ "[error] greater-than is not defined for " ++ show a ++ ", " ++ show b +lGreaterThan :: LWord -> LWord -> ExceptT LException IO LWord +lGreaterThan (LInteger a) (LInteger b) = pure $ LBool (a > b) +lGreaterThan (LFloat a) (LFloat b) = pure $ LBool (a > b) +lGreaterThan a b = throwError $ LException $ "greater-than is not defined for " ++ show a ++ ", " ++ show b -lLesserThan (LInteger a) (LInteger b) = LBool (a < b) -lLesserThan (LFloat a) (LFloat b) = LBool (a < b) -lLesserThan a b = error $ "[error] lesser-than is not defined for " ++ show a ++ ", " ++ show b +lLesserThan :: LWord -> LWord -> ExceptT LException IO LWord +lLesserThan (LInteger a) (LInteger b) = pure $ LBool (a < b) +lLesserThan (LFloat a) (LFloat b) = pure $ LBool (a < b) +lLesserThan a b = throwError $ LException $ "lesser-than is not defined for " ++ show a ++ ", " ++ show b -lModNumbers (LInteger a) (LInteger b) = LInteger (a `mod` b) -lModNumbers a b = error $ "[error] modulo is not defined for " ++ show a ++ ", " ++ show b +lModNumbers :: LWord -> LWord -> ExceptT LException IO LWord +lModNumbers (LInteger a) (LInteger b) = pure $ LInteger (a `mod` b) +lModNumbers a b = throwError $ LException $ "modulo is not defined for " ++ show a ++ ", " ++ show b |
