diff options
| author | Jan Tuomi <jans.tuomi@gmail.com> | 2022-02-06 19:05:46 +0200 |
|---|---|---|
| committer | Jan Tuomi <jans.tuomi@gmail.com> | 2022-02-06 20:03:27 +0200 |
| commit | d5fe35bb8a75a74c7b3616b864c4d35bafecaadd (patch) | |
| tree | 410325cafa976dfa0596872d8c0582e1b36772c0 /src/interpreter.hs | |
| parent | c2053ee0585280229375b10283cb9e8dbb903734 (diff) | |
Add proper cabal setup
Diffstat (limited to 'src/interpreter.hs')
| -rw-r--r-- | src/interpreter.hs | 233 |
1 files changed, 0 insertions, 233 deletions
diff --git a/src/interpreter.hs b/src/interpreter.hs deleted file mode 100644 index cb71c62..0000000 --- a/src/interpreter.hs +++ /dev/null @@ -1,233 +0,0 @@ -module Interpreter where - -import Control.Monad.Except -import Data.Char -import Data.Map (Map, (!)) -import qualified Data.Map as M -import LTypes -import Utils - -debugWaitForChar Config {configDebugMode = mode} = do - if mode - then do - c <- getChar - pure $ case c of - 'q' -> ExecExit - _ -> ExecContinue - else pure ExecContinue - -debugPrint Config {configDebugMode = mode} message = - if mode - then liftIO $ putStrLn $ fmt "[debug] %%" [message] - else pure () - -interpretSource :: Config -> LState -> ExceptT LException IO LState -interpretSource config state@LState {lSource = []} = pure state -interpretSource config state@LState {lSource = (word : rest)} = do - liftIO $ debugPrint config $ fmt "processing %%, current state =" [show word] - liftIO $ debugState config state - newState <- interpretWord state {lSource = rest} word - step <- liftIO $ debugWaitForChar config - case step of - ExecContinue -> interpretSource config newState - ExecExit -> pure newState - -interpretWord :: LState -> LWord -> ExceptT LException IO LState --- non-nestable structures -interpretWord state@LState {lStack = stack, lPhraseDepth = phraseDepth} word@(LSymbol "define") = - pure $ - state - { lPhraseDepth = phraseDepth + 1, - lStack = word : stack - } -interpretWord state@LState {lDefs = defs, lStack = stack, lPhraseDepth = phraseDepth} word@(LSymbol ";") = do - let defineSpan = takeWhile (\word -> word /= LSymbol "define") stack - let newStack = dropWhile (\word -> word /= LSymbol "define") stack $> tail - (LSymbol identifier, body) <- consume1 LSymbolT (reverse defineSpan) - let newDefs = M.insert identifier body defs - pure $ - state - { lPhraseDepth = phraseDepth - 1, - lDefs = newDefs, - lStack = newStack - } --- words that simply move from source to stack -interpretWord state@LState {lStack = stack} word@(LInteger _) = pure $ state {lStack = word : stack} -interpretWord state@LState {lStack = stack} word@(LFloat _) = pure $ state {lStack = word : stack} -interpretWord state@LState {lStack = stack} word@(LBool _) = pure $ state {lStack = word : stack} -interpretWord state@LState {lStack = stack} word@(LChar _) = pure $ state {lStack = word : stack} -interpretWord state@LState {lStack = stack} word@(LLabel _) = pure $ state {lStack = word : stack} -interpretWord state@LState {lStack = stack} word@(LPhrase _) = pure $ state {lStack = word : stack} --- string literals -interpretWord state@LState {lSource = source, lStrLitRefMap = strLitRefMap} (LStringLitRef ref) = - let strLitP = strLitRefMap ! ref - in pure $ state {lSource = strLitP ++ source} --- phrase markers are always evaled -interpretWord state@LState {lStack = stack, lPhraseDepth = phraseDepth} word@(LSymbol "[") = - pure $ state {lPhraseDepth = phraseDepth + 1, lStack = word : stack} -interpretWord state@LState {lStack = stack, lPhraseDepth = phraseDepth} word@(LSymbol "]") = do - (phrase, _ : stack') <- safeBreak (== LSymbol "[") (LException "phrase-start marker '[' missing in stack") stack - let newStack = LPhrase (reverse phrase) : stack' - pure $ state {lPhraseDepth = phraseDepth - 1, lStack = newStack} --- definition lookup -interpretWord state@LState {lDefs = defs, lDict = dict, lSource = source, lPhraseDepth = phraseDepth, lStack = stack} word@(LSymbol symbol) - | phraseDepth == 0 = - case M.lookup symbol defs of - Just body -> pure $ state {lSource = body ++ source} - Nothing -> - case symbol of - "dup" -> pure $ state {lStack = head stack : stack} - "drop" -> pure $ state {lStack = tail stack} - "clear" -> pure $ state {lStack = []} - "noop" -> pure state - "true" -> pure $ state {lStack = LBool True : stack} - "false" -> pure $ state {lStack = LBool False : stack} - "not" -> do - (LBool a, stack') <- consume1 LBoolT stack - pure $ state {lStack = LBool (not a) : stack'} - "float" -> do - (LInteger a, stack') <- consume1 LIntegerT stack - pure $ state {lStack = LFloat (fromIntegral a) : stack'} - "round" -> do - (LFloat a, stack') <- consume1 LFloatT stack - pure $ state {lStack = LInteger (round a) : stack'} - "!" -> do - (LLabel a, b, stack') <- consume2 LLabelT AnyT stack - let newDict = M.insert a b dict - pure $ state {lDict = newDict, lStack = stack'} - "@" -> do - (LLabel a, stack') <- consume1 LLabelT stack - let lookupWord = dict ! a - pure $ state {lStack = lookupWord : stack'} - "forget" -> do - (LLabel a, stack') <- consume1 LLabelT stack - let newDict = M.delete a dict - pure $ state {lStack = stack', lDict = newDict} - "." -> do - (a, stack') <- consume1 AnyT stack - liftIO . putStrLn $ reprWord a - pure $ state {lStack = stack'} - "s." -> do - (wordP, stack') <- consume1 LPhraseT stack - let LPhrase ws = wordP - let isLChar w = case w of LChar _ -> True; _ -> False - unless (all isLChar ws) $ throwError $ LException $ fmt "cannot string-print heterogenous or non-string phrase: %%" [reprWord wordP] - let stringRepr = ws $> map (\(LChar c) -> c) - liftIO . putStrLn $ stringRepr - pure $ state {lStack = stack'} - "?" -> do - (LLabel a, stack') <- consume1 LLabelT stack - let lookupWord = dict ! a - liftIO . putStrLn $ reprWord lookupWord - pure $ state {lStack = stack'} - "+" -> do - (a, b, stack') <- consume2 AnyT AnyT stack - result <- lAddNumbers b a - pure $ state {lStack = result : stack'} - "-" -> do - (a, b, stack') <- consume2 AnyT AnyT stack - result <- lSubNumbers b a - pure $ state {lStack = result : stack'} - "*" -> do - (a, b, stack') <- consume2 AnyT AnyT stack - result <- lMultiplyNumbers b a - pure $ state {lStack = result : stack'} - "/" -> do - (a, b, stack') <- consume2 AnyT AnyT stack - result <- lDivideNumbers b a - pure $ state {lStack = result : stack'} - "mod" -> do - (a, b, stack') <- consume2 AnyT AnyT stack - result <- lModNumbers b a - pure $ state {lStack = result : stack'} - "eq?" -> do - (a, b, stack') <- consume2 AnyT AnyT stack - pure $ state {lStack = LBool (a == b) : stack'} - "gt?" -> do - (a, b, stack') <- consume2 AnyT AnyT stack - result <- lGreaterThan b a - pure $ state {lStack = result : stack'} - "lt?" -> do - (a, b, stack') <- consume2 AnyT AnyT stack - result <- lLesserThan b a - pure $ state {lStack = result : stack'} - "unphrase" -> do - (LPhrase phrase, stack') <- consume1 LPhraseT stack - pure $ state {lSource = phrase ++ source, lStack = stack'} - "phrase" -> do - (LSymbol "]", stack') <- consume1 LSymbolT stack - (body, _ : newStack) <- safeBreak (== LSymbol "[") (LException "phrase-start marker '[' missing in stack") stack' - pure $ state {lStack = LPhrase (reverse body) : newStack} - "repr" -> do - (word, stack') <- consume1 AnyT stack - let reprStr = reprWord word $> map LChar .> LPhrase - pure $ state {lStack = reprStr : stack'} - "pop" -> do - (LPhrase phrase, stack') <- consume1 LPhraseT stack - let (first : rest) = phrase - pure $ state {lStack = first : LPhrase rest : stack'} - "stack-size" -> - let size = LInteger $ fromIntegral (length stack) - in pure $ state {lStack = size : stack} - "']" -> - pure $ state {lStack = LSymbol "]" : stack} - "'[" -> - pure $ state {lStack = LSymbol "[" : stack} - "cond" -> do - (fb, tb, LBool cond, stack') <- consume3 LPhraseT LPhraseT LBoolT stack - let LPhrase branch = if cond then tb else fb - let newSource = branch ++ source - pure $ state {lStack = stack', lSource = newSource} - "loop" -> do - (bodyP, condP, stack') <- consume2 LPhraseT LPhraseT stack - let (LPhrase body, LPhrase cond) = (bodyP, condP) - let ifWords = - concat - [ cond, - [LPhrase (body ++ [condP, bodyP, LSymbol "loop"])], - [LPhrase [], LSymbol "cond"] - ] - let newSource = ifWords ++ source - pure $ state {lStack = stack', lSource = newSource} - _ -> throwError $ LException $ fmt "not defined: %%" [symbol] - | otherwise = pure $ state {lStack = word : stack} - -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 $ fmt "sum 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 $ fmt "difference 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 $ fmt "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 $ fmt "division 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 $ fmt "greater-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 $ fmt "lesser-than 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 $ fmt "modulo is not defined for %%, %%" [show a, show b] |
