diff options
| author | Jan Tuomi <jans.tuomi@gmail.com> | 2022-01-30 18:48:29 +0200 |
|---|---|---|
| committer | Jan Tuomi <jans.tuomi@gmail.com> | 2022-01-30 18:48:29 +0200 |
| commit | 542b0d035444416cae8994f89d1ae11c4e4c5df9 (patch) | |
| tree | 3c930e750a679b834fe5373ae8249ae1e7676f67 | |
| parent | 3fbe17312a7b1474b290c129ebeca9ee7c773c6e (diff) | |
Move interpreter stuff under interpreter.hs
| -rw-r--r-- | src/interpreter.hs | 214 | ||||
| -rw-r--r-- | src/ltypes.hs | 30 | ||||
| -rw-r--r-- | src/main.hs | 238 |
3 files changed, 245 insertions, 237 deletions
diff --git a/src/interpreter.hs b/src/interpreter.hs new file mode 100644 index 0000000..6eb6697 --- /dev/null +++ b/src/interpreter.hs @@ -0,0 +1,214 @@ +module Interpreter where + +import Data.Char +import Data.Map (Map, (!)) +import qualified Data.Map as M +import LTypes +import System.IO (BufferMode (NoBuffering), hSetBuffering, stdin) +import Utils + +debugWaitForChar Config {configDebugMode = mode} = + if mode + then do + hSetBuffering stdin NoBuffering + c <- getChar + pure $ case c of + 'q' -> ExecExit + _ -> ExecContinue + else pure ExecContinue + +debugPrint Config {configDebugMode = mode} message = + if mode + then putStrLn $ "[debug] " ++ message + else pure () + +interpretSource :: Config -> LState -> 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 + case step of + ExecContinue -> interpretSource config newState + ExecExit -> pure () + +interpretWord :: LState -> LWord -> 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 ";") = + let defineSpan = takeWhile (\word -> word /= LSymbol "define") stack + newStack = dropWhile (\word -> word /= LSymbol "define") stack $> tail + ((LSymbol identifier) : body) = reverse defineSpan + newDefs = M.insert identifier body defs + in 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 "]") = + let (phrase, stack') = break (== LSymbol "[") stack + newStack = LPhrase (reverse phrase) : tail stack' + in 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" -> + let (LBool a : stack') = stack + in pure $ state {lStack = LBool (not a) : stack'} + "float" -> + let (LInteger a : stack') = stack + in pure $ state {lStack = LFloat (fromIntegral a) : stack'} + "round" -> + let (LFloat a : stack') = stack + in pure $ state {lStack = LInteger (round a) : stack'} + "!" -> + let (LLabel a : b : stack') = stack + newDict = M.insert a b dict + in pure $ state {lDict = newDict, lStack = stack'} + "@" -> + let (LLabel a : stack') = stack + lookupWord = dict ! a + in pure $ state {lStack = lookupWord : stack'} + "forget" -> + let (LLabel a : stack') = stack + newDict = M.delete a dict + in pure $ state {lStack = stack', lDict = newDict} + "." -> do + let (a : stack') = stack + 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 () + let stringRepr = ws $> map (\(LChar c) -> c) + putStrLn stringRepr + pure $ state {lStack = stack'} + "?" -> do + let (LLabel a : stack') = stack + let lookupWord = dict ! a + putStrLn $ reprWord lookupWord + pure $ state {lStack = stack'} + "+" -> + let (a : b : stack') = stack + result = lAddNumbers b a + in pure $ state {lStack = result : stack'} + "-" -> + let (a : b : stack') = stack + result = lSubNumbers b a + in pure $ state {lStack = result : stack'} + "*" -> + let (a : b : stack') = stack + result = lMultiplyNumbers b a + in pure $ state {lStack = result : stack'} + "/" -> + let (a : b : stack') = stack + result = lDivideNumbers b a + in pure $ state {lStack = result : stack'} + "mod" -> + let (a : b : stack') = stack + result = lModNumbers b a + in pure $ state {lStack = result : stack'} + "eq?" -> + let (a : b : stack') = stack + in pure $ state {lStack = LBool (a == b) : stack'} + "gt?" -> + let (a : b : stack') = stack + in pure $ state {lStack = lGreaterThan b a : stack'} + "lt?" -> + let (a : b : stack') = stack + in pure $ state {lStack = lLesserThan b a : stack'} + "unphrase" -> + let (LPhrase phrase : stack') = stack + in pure $ state {lSource = phrase ++ source, lStack = stack'} + "phrase" -> + let (LSymbol "]" : stack') = stack + (body, _ : newStack) = break (== LSymbol "[") stack' + in pure $ state {lStack = LPhrase (reverse body) : newStack} + "repr" -> + let (word : stack') = stack + reprStr = reprWord word $> map LChar .> LPhrase + in pure $ state {lStack = reprStr : stack'} + "pop" -> + let (LPhrase phrase : stack') = stack + (first : rest) = phrase + in 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" -> + let (fb : tb : (LBool cond) : stack') = stack + LPhrase branch = if cond then tb else fb + newSource = branch ++ source + in pure $ state {lStack = stack', lSource = newSource} + "loop" -> + let (bodyP@(LPhrase body) : condP@(LPhrase cond) : stack') = stack + 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 + | 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 + +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 + +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 + +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 + +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 + +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 + +lModNumbers (LInteger a) (LInteger b) = LInteger (a `mod` b) +lModNumbers a b = error $ "[error] modulo is not defined for " ++ show a ++ ", " ++ show b diff --git a/src/ltypes.hs b/src/ltypes.hs index bb7e0de..27fdd35 100644 --- a/src/ltypes.hs +++ b/src/ltypes.hs @@ -1,5 +1,7 @@ module LTypes where +import Data.Map (Map) +import qualified Data.Map as M import Utils data LWord @@ -22,3 +24,31 @@ reprWord (LChar a) = show a reprWord (LLabel a) = a reprWord (LStringLitRef a) = "StrLit(" ++ a ++ ")" reprWord (LPhrase a) = "P[ " ++ map reprWord a $> unwords ++ " ]" + +data LState = LState + { lDict :: Map String LWord, + lStack :: [LWord], + lPhraseDepth :: Int, + lDefs :: Map String [LWord], + lSource :: [LWord], + lStrLitRefMap :: Map String [LWord] + } + deriving (Show) + +data Config = Config + { configFileNameM :: Maybe String, + configDebugMode :: Bool + } + +data ExecStep = ExecContinue | ExecExit + +debugState Config {configDebugMode = mode} state = + if mode + then do + putStrLn $ "stack: " ++ unwords (map reprWord (lStack state)) + putStrLn $ "source: " ++ unwords (map reprWord (lSource state)) + putStrLn $ "defs: " ++ unwords (M.keys (lDefs state)) + putStrLn $ "dict: " ++ unwords (M.keys (lDict state)) + putStrLn $ "lPhraseDepth: " ++ show (lPhraseDepth state) + putStrLn "" + else pure () diff --git a/src/main.hs b/src/main.hs index c67cea0..6582b38 100644 --- a/src/main.hs +++ b/src/main.hs @@ -4,17 +4,12 @@ import Data.Char import Data.Map (Map, (!)) import qualified Data.Map as M import Debug.Trace (trace, traceShow) +import Interpreter import LTypes import Parser import System.Environment (getArgs) -import System.IO (BufferMode (NoBuffering), hSetBuffering, stdin) import Utils -data Config = Config - { configFileNameM :: Maybe String, - configDebugMode :: Bool - } - getConfig config [] = config getConfig config ("--debug" : rest) = let newConfig = config {configDebugMode = True} @@ -23,237 +18,6 @@ getConfig config (fileName : rest) = let newConfig = config {configFileNameM = Just fileName} in getConfig newConfig rest -debugPrint Config {configDebugMode = mode} message = - if mode - then putStrLn $ "[debug] " ++ message - else pure () - -data LState = LState - { lDict :: Map String LWord, - lStack :: [LWord], - lPhraseDepth :: Int, - lDefs :: Map String [LWord], - lSource :: [LWord], - lStrLitRefMap :: Map String [LWord] - } - deriving (Show) - -evalMode state = lPhraseDepth state == 0 - -debugState Config {configDebugMode = mode} state = - if mode - then do - putStrLn $ "stack: " ++ unwords (map reprWord (lStack state)) - putStrLn $ "source: " ++ unwords (map reprWord (lSource state)) - putStrLn $ "defs: " ++ unwords (M.keys (lDefs state)) - putStrLn $ "dict: " ++ unwords (M.keys (lDict state)) - putStrLn $ "lPhraseDepth: " ++ show (lPhraseDepth state) - putStrLn "" - else pure () - -data ExecStep = ExecContinue | ExecExit - -debugWaitForChar Config {configDebugMode = mode} = - if mode - then do - hSetBuffering stdin NoBuffering - c <- getChar - pure $ case c of - 'q' -> ExecExit - _ -> ExecContinue - else pure ExecContinue - -interpretSource :: Config -> LState -> 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 - case step of - ExecContinue -> interpretSource config newState - ExecExit -> pure () - -interpretWord :: LState -> LWord -> 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 ";") = - let defineSpan = takeWhile (\word -> word /= LSymbol "define") stack - newStack = dropWhile (\word -> word /= LSymbol "define") stack $> tail - ((LSymbol identifier) : body) = reverse defineSpan - newDefs = M.insert identifier body defs - in 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 "]") = - let (phrase, stack') = break (== LSymbol "[") stack - newStack = LPhrase (reverse phrase) : tail stack' - in 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" -> - let (LBool a : stack') = stack - in pure $ state {lStack = LBool (not a) : stack'} - "float" -> - let (LInteger a : stack') = stack - in pure $ state {lStack = LFloat (fromIntegral a) : stack'} - "round" -> - let (LFloat a : stack') = stack - in pure $ state {lStack = LInteger (round a) : stack'} - "!" -> - let (LLabel a : b : stack') = stack - newDict = M.insert a b dict - in pure $ state {lDict = newDict, lStack = stack'} - "@" -> - let (LLabel a : stack') = stack - lookupWord = dict ! a - in pure $ state {lStack = lookupWord : stack'} - "forget" -> - let (LLabel a : stack') = stack - newDict = M.delete a dict - in pure $ state {lStack = stack', lDict = newDict} - "." -> do - let (a : stack') = stack - 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 () - let stringRepr = ws $> map (\(LChar c) -> c) - putStrLn stringRepr - pure $ state {lStack = stack'} - "?" -> do - let (LLabel a : stack') = stack - let lookupWord = dict ! a - putStrLn $ reprWord lookupWord - pure $ state {lStack = stack'} - "+" -> - let (a : b : stack') = stack - result = lAddNumbers b a - in pure $ state {lStack = result : stack'} - "-" -> - let (a : b : stack') = stack - result = lSubNumbers b a - in pure $ state {lStack = result : stack'} - "*" -> - let (a : b : stack') = stack - result = lMultiplyNumbers b a - in pure $ state {lStack = result : stack'} - "/" -> - let (a : b : stack') = stack - result = lDivideNumbers b a - in pure $ state {lStack = result : stack'} - "mod" -> - let (a : b : stack') = stack - result = lModNumbers b a - in pure $ state {lStack = result : stack'} - "eq?" -> - let (a : b : stack') = stack - in pure $ state {lStack = LBool (a == b) : stack'} - "gt?" -> - let (a : b : stack') = stack - in pure $ state {lStack = lGreaterThan b a : stack'} - "lt?" -> - let (a : b : stack') = stack - in pure $ state {lStack = lLesserThan b a : stack'} - "unphrase" -> - let (LPhrase phrase : stack') = stack - in pure $ state {lSource = phrase ++ source, lStack = stack'} - "phrase" -> - let (LSymbol "]" : stack') = stack - (body, _ : newStack) = break (== LSymbol "[") stack' - in pure $ state {lStack = LPhrase (reverse body) : newStack} - "repr" -> - let (word : stack') = stack - reprStr = reprWord word $> map LChar .> LPhrase - in pure $ state {lStack = reprStr : stack'} - "pop" -> - let (LPhrase phrase : stack') = stack - (first : rest) = phrase - in 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" -> - let (fb : tb : (LBool cond) : stack') = stack - LPhrase branch = if cond then tb else fb - newSource = branch ++ source - in pure $ state {lStack = stack', lSource = newSource} - "loop" -> - let (bodyP@(LPhrase body) : condP@(LPhrase cond) : stack') = stack - 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 - | 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 - -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 - -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 - -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 - -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 - -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 - -lModNumbers (LInteger a) (LInteger b) = LInteger (a `mod` b) -lModNumbers a b = error $ "[error] modulo is not defined for " ++ show a ++ ", " ++ show b - main :: IO () main = do args <- getArgs |
