forked from thulsadum/false-hs
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Interpreter.hs
228 lines (161 loc) · 5.37 KB
/
Interpreter.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module False.Interpreter where
import Control.Monad.RWS.Strict
import Control.Monad.Trans.Either
import qualified Data.Map.Strict as Map
import Data.Map.Strict (Map)
import Data.Bits
import Data.Char ( ord
, chr
)
import System.IO ( hFlush
, stdin
, stdout
)
import Utils
import False.Parser
type FIEnv = ()
data FIState i = FIState { stack :: [i]
, variables :: Map Char i
, lambdas :: Map i [FalseToken i]
, currentLambda :: i
}
type FIWriter = ()
newtype FalseInterpreter i a =
FalseInterpreter { unwrap
:: RWST FIEnv FIWriter (FIState i) (EitherT String IO) a }
deriving ( Functor, Applicative, Monad
, MonadState (FIState i), MonadReader FIEnv, MonadWriter FIWriter
, MonadIO)
type FI i = FalseInterpreter i i
emptyState :: (Integral i) => FIState i
emptyState = FIState { stack = []
, variables = Map.empty
, lambdas = Map.empty
, currentLambda = 0
}
defaultEnv :: FIEnv
defaultEnv = ()
interpretingError :: String -> FalseInterpreter i a
interpretingError msg = FalseInterpreter $ lift $ left msg
pop :: FI i
pop = do
FIState { stack = stack } <- get
case stack of
[] -> interpretingError "stack underflow"
(x:xs) -> do
modify $ \s -> s { stack = xs}
return x
push :: i -> FalseInterpreter i ()
push x = do
modify $ \s@(FIState {stack = xs}) -> s {stack = (x:xs)}
-- | returns the nth element of the stack
peek :: Int -> FI i
peek n = do
FIState {stack = stack } <- get
case subscript stack n of
Nothing -> interpretingError "stack underflow"
Just x -> return x
top :: FI i
top = peek 0
getVar :: (Num i) => Char -> FI i
getVar var = do
FIState { variables = vars } <- get
return $ Map.findWithDefault 0 var vars
putVar :: Char -> i -> FalseInterpreter i ()
putVar var val = modify $ \(st@FIState {variables = vars}) ->
st { variables = Map.alter f var vars }
where f _ = return val
addLambda :: (Num i, Ord i) => [FalseToken i] -> FalseInterpreter i ()
addLambda ts = do
st@(FIState { lambdas = ls }) <- get
let id = fromIntegral . Map.size $ ls
put $ st { lambdas = Map.insert id ts ls }
push id
getLambda :: (Ord i) => i -> FalseInterpreter i [FalseToken i]
getLambda i = do
FIState { lambdas = ls } <- get
return $ Map.findWithDefault [] i ls
evalBinOp :: (i->i->i) -> FalseInterpreter i ()
evalBinOp rel = do
op1 <- pop
op2 <- pop
push $ op2 `rel` op1
evalOp :: (i->i) -> FalseInterpreter i ()
evalOp f = pop >>= push . f
-- TODO improve error handling
evalStep :: (Integral i, Bits i, Show i) => FalseToken i -> FalseInterpreter i ()
evalStep Add = evalBinOp (+)
evalStep Sub = evalBinOp (-) -- NOTE: is this the correct operand order?
evalStep Mul = evalBinOp (*)
evalStep Div = evalBinOp div
evalStep Neg = evalOp (0-)
evalStep Eq = evalBinOp $ \a b -> if a == b then -1 else 0
evalStep Gt = evalBinOp $ \a b -> if a > b then -1 else 0
evalStep And = evalBinOp (.&.)
evalStep Or = evalBinOp (.|.)
evalStep Not = evalOp complement
evalStep (IntLit n) = push n
evalStep (CharLit ch) = push . fromIntegral . ord $ ch
evalStep (PutVar v) = pop >>= putVar v
evalStep (GetVar v) = getVar v >>= push
evalStep (Lambda ts) = addLambda ts
evalStep Apply = pop >>= getLambda >>= eval_
evalStep Dup = top >>= push
evalStep Drop = pop >> return ()
evalStep Swap = do
val1 <- pop
val2 <- pop
push val1
push val2
evalStep Rot = do
val1 <- pop
val2 <- pop
val3 <- pop
push val2
push val1
push val3
evalStep Pick = do
n <- pop
val <- peek . fromIntegral $ n
push val
evalStep When = do
l <- pop
cond <- pop
if cond == 0
then return ()
else getLambda l >>= eval_
evalStep While = do
lbody <- pop
lcond <- pop
getLambda lcond >>= eval_
cond <- pop
if cond == 0
then return ()
else do
getLambda lbody >>= eval_
push lcond >> push lbody
evalStep While
evalStep (Print msg) = liftIO . putStr $ msg
evalStep PrintInt = pop >>= (liftIO . putStr . show)
evalStep Putch = pop >>= (liftIO . putChar . chr . fromIntegral)
evalStep Getch = liftIO getChar >>= (push . fromIntegral . ord)
evalStep Flush = (liftIO $ hFlush stdin) >> (liftIO $ hFlush stdout)
runFalseInterpreter :: FalseInterpreter i a -> FIEnv -> (FIState i)
-> IO (Either String a)
runFalseInterpreter interp env st =
runEitherT $ extract <$> (runRWST . unwrap) interp env st
where extract = \(a,_,_) -> a
runFalseInterpreter' :: (Integral i) => FalseInterpreter i a -> IO (Either String a)
runFalseInterpreter' interp = runFalseInterpreter interp defaultEnv emptyState
eval :: (Integral i, Bits i, Show i) => [FalseToken i] -> FalseInterpreter i [i]
eval ts = do
mapM_ evalStep ts
FIState { stack = stack } <- get
return stack
eval_ :: (Integral i, Bits i, Show i) => [FalseToken i] -> FalseInterpreter i ()
eval_ ts = eval ts >> return ()
runEval :: (Integral i, Bits i, Show i) => [FalseToken i] -> IO (Either String [i])
runEval = runFalseInterpreter' . eval
runEval_ :: (Integral i, Bits i, Show i) => [FalseToken i] -> IO (Either String ())
runEval_ = runFalseInterpreter' . eval_