1 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
2 {-# LANGUAGE FlexibleContexts #-}
3 {-# LANGUAGE FlexibleInstances #-}
4 {-# LANGUAGE LambdaCase #-}
5 {-# LANGUAGE MultiParamTypeClasses #-}
11 import qualified Data.Map as DM
12 import Control.Monad.Writer
13 import Control.Monad.State
14 import Control.Monad.ST
20 newtype Compiler a = Compiler { unCompiler :: StateT CS (WriterT [Instr] (Either String)) a }
28 instance MonadFail Compiler where fail s = Compiler $ lift $ lift $ Left s
31 , functions :: DM.Map Int [Instr]
34 runCompiler :: Compiler a -> Either String [Instr]
35 runCompiler c = execWriterT
36 $ evalStateT (unCompiler (c >> instr [Halt] >> writeFunctions))
37 $ CS {fresh=[0..], functions=DM.empty}
39 writeFunctions :: Compiler ()
40 writeFunctions = gets (DM.elems . functions) >>= tell . concat
42 instr :: [Instr] -> Compiler a
43 instr i = tell i >> pure undefined
45 freshLabel :: Compiler Int
46 freshLabel = get >>= \cs->put (cs { fresh=tail (fresh cs) }) >> pure (head $ fresh cs)
48 binop :: Instr -> Compiler a1 -> Compiler a2 -> Compiler b
49 binop i l r = l >> r >> instr [i]
51 unop :: Instr -> Compiler a -> Compiler b
52 unop i l = l >> instr [i]
54 instance Expression Compiler where
55 lit v = instr $ map Push $ serialise v []
61 -- (^.) l r = freshLabel >>= \lblstart->freshLabel >>= \lblend->
62 -- l >> r >> instr -- pow (x, y) {
65 -- , Push 1 -- res = 1
66 -- , Lbl lblstart -- while
67 -- , Ldr 1 -- (y == 0)
71 -- , Ldr 0 -- res *= x
90 if' p t e = freshLabel >>= \elselabel-> freshLabel >>= \endiflabel->
91 p >> instr [Brf elselabel] >>
92 t >> instr [Bra endiflabel, Lbl elselabel] >>
93 e >> instr [Lbl endiflabel]
94 bottom msg = instr [Error msg]
96 instance Function () Compiler where
98 freshLabel >>= \funlabel->
99 let g :- m = def (\()->instr [Jsr funlabel])
100 in liftFunction funlabel 0 (g ()) >> unmain m
102 instance Function (Compiler a) Compiler where
104 freshLabel >>= \funlabel->
105 let g :- m = def (\a->a >> instr [Jsr funlabel])
106 in liftFunction funlabel 1 (g (instr [Arg 0])) >> unmain m
108 instance Function (Compiler a, Compiler b) Compiler where
110 freshLabel >>= \funlabel->
111 let g :- m = def (\(a, b)->a >> b >> instr [Jsr funlabel])
112 in liftFunction funlabel 2 (g (instr [Arg 1], instr [Arg 0])) >> unmain m
114 instance Function (Compiler a, Compiler b, Compiler c) Compiler where
116 freshLabel >>= \funlabel->
117 let g :- m = def (\(a, b, c)->a >> b >> c >> instr [Jsr funlabel])
118 in liftFunction funlabel 3 (g (instr [Arg 2], instr [Arg 1], instr [Arg 0])) >> unmain m
120 liftFunction :: Int -> Int -> Compiler a -> Compiler ()
121 liftFunction lbl nargs body = do
122 is <- snd <$> censor (\_->[]) (listen body)
123 let instructions = Lbl lbl : is ++ [Ret nargs]
124 modify (\s->s { functions=DM.insert lbl instructions $ functions s })
127 = Push Int | Pop Int -- | Dup | Roll Int Int
128 | Add | Sub | Mul | Div | Neg | Pow
130 | Eq | Neq | Le | Ge | Leq | Geq
131 | Lbl Int | Bra Int | Brf Int
134 | Jsr Int | Ret Int | Arg Int
135 | Halt | Error String
138 data Registers = Registers
143 , gp :: DM.Map Int Int
147 interpret :: Int -> [Instr] -> Int
148 interpret memsize prog = runSTArray resultStack ! (memsize-1)
150 resultStack :: ST s (STArray s Int Int)
151 resultStack = join $ int
152 <$> newListArray (0, length prog) prog
153 <*> newArray (0, memsize-1) 0
154 <*> pure (Registers {pc=0, sp=memsize-1, mp=0, hp=0, gp=DM.empty})
156 pushh :: STArray s Int Int -> Int -> Registers -> ST s Registers
157 pushh memory value reg = do
158 writeArray memory (hp reg) value
159 pure (reg { hp = hp reg + 1} )
161 loadh :: STArray s Int Int -> Int -> Registers -> ST s Registers
162 loadh memory hptr registers = readArray memory hptr >>= flip (push memory) registers
164 push :: STArray s Int Int -> Int -> Registers -> ST s Registers
165 push memory value reg = do
166 writeArray memory (sp reg) value
167 pure (reg { sp = sp reg - 1} )
169 pop :: STArray s Int Int -> Registers -> ST s (Registers, Int)
171 v <- readArray memory (sp reg + 1)
172 pure (reg { sp = sp reg + 1}, v)
174 popn :: STArray s Int Int -> Int -> Registers -> ST s (Registers, [Int])
175 popn _ 0 reg = pure (reg, [])
176 popn memory n reg = do
177 (reg', v) <- pop memory reg
178 (reg'', vs) <- popn memory (n - 1) reg'
181 bop :: (Int -> Int -> Int) -> STArray s Int Int -> Registers -> ST s Registers
182 bop op memory reg = do
183 (reg1, r) <- pop memory reg
184 uop (flip op r) memory reg1
186 uop :: (Int -> Int) -> STArray s Int Int -> Registers -> ST s Registers
187 uop op memory reg = do
188 (reg1, r) <- pop memory reg
189 push memory (op r) reg1
191 int :: STArray s Int Instr -> STArray s Int Int -> Registers -> ST s (STArray s Int Int)
192 int program memory registers = do
193 instruction <- readArray program $ pc registers
194 stack <- getElems memory
195 let reg = registers { pc = pc registers + 1 }
196 case trace ("Interpret: " ++ show instruction ++ " with registers: " ++ show registers ++ " and stack: " ++ show stack) instruction of
197 -- case instruction of
199 (reg', v) <- pop memory reg
200 int program memory $ reg' { gp = DM.insert r v (gp reg')}
201 Ldr r -> push memory (DM.findWithDefault 0 r $ gp reg) reg >>= int program memory
202 -- Roll 0 _ -> int program memory reg
203 -- Roll 1 _ -> int program memory reg
204 -- Roll _ 0 -> int program memory reg
205 -- Roll depth num -> do
206 -- (reg', vs) <- popn memory depth reg
207 -- foldM (flip $ push memory) reg' (roll num [] $ reverse vs) >>= int program memory
209 -- roll 0 acc vs = vs ++ reverse acc
210 -- roll n acc [] = roll n [] $ reverse acc
211 -- roll n acc (v:vs) = roll (n-1) (v:acc) vs
212 Pop n -> popn memory n reg >>= int program memory . fst
213 Push v -> push memory v reg >>= int program memory
214 -- Dup -> pop memory reg >>= \(r', v)->push memory v r' >>= push memory v >>= int program memory
215 Add -> bop (+) memory reg >>= int program memory
216 Sub -> bop (-) memory reg >>= int program memory
217 Mul -> bop (*) memory reg >>= int program memory
218 Div -> bop div memory reg >>= int program memory
219 Neg -> uop negate memory reg >>= int program memory
220 Pow -> bop (^) memory reg >>= int program memory
221 And -> bop ((b2i .) . on (&&) i2b) memory reg >>= int program memory
222 Or -> bop ((b2i .) . on (||) i2b) memory reg >>= int program memory
223 Not -> uop (b2i . Prelude.not . i2b) memory reg >>= int program memory
224 Eq -> bop ((b2i .) . (==)) memory reg >>= int program memory
225 Neq -> bop ((b2i .) . (/=)) memory reg >>= int program memory
226 Le -> bop ((b2i .) . (<)) memory reg >>= int program memory
227 Ge -> bop ((b2i .) . (>)) memory reg >>= int program memory
228 Leq -> bop ((b2i .) . (<=)) memory reg >>= int program memory
229 Geq -> bop ((b2i .) . (>=)) memory reg >>= int program memory
230 Lbl _ -> int program memory reg
231 Bra l -> branch l program reg >>= int program memory
233 (reg', v) <- pop memory reg
234 reg'' <- if i2b v then pure reg' else branch l program reg'
235 int program memory reg''
238 >>= uncurry (foldM $ flip $ pushh memory)
239 >>= push memory (hp reg + n - 1)
240 >>= int program memory
241 Ldh n -> pop memory reg >>= \(reg', hptr)->loadh memory (hptr - n - 1) reg'
242 >>= int program memory
243 Jsr i -> push memory (pc reg) reg
244 >>= push memory (mp reg)
246 >>= \r->int program memory (r { mp = sp r})
248 (reg1, rval:omp:ra:_) <- popn memory (3+n) reg
249 reg2 <- push memory rval reg1
250 int program memory $ reg2 { pc=ra, mp=omp }
252 v <- readArray memory (mp reg + 3 + n)
253 push memory v reg >>= int program memory
255 Error msg -> fail msg
257 branch :: Int -> STArray s Int Instr -> Registers -> ST s Registers
258 branch label program reg = case pc reg of
259 -1 -> getBounds program >>= \(_, m)->branch label program $ reg { pc = m - 1}
260 _ -> readArray program (pc reg) >>= \case
261 Lbl l | label == l -> pure $ reg
262 _ -> branch label program $ reg { pc = pc reg - 1 }