never executed always true always false
1 module HelVM.HelMA.Automata.ETA.Automaton (
2 run,
3 newMemory,
4 ) where
5
6 import HelVM.HelMA.Automata.ETA.Addressing
7 import HelVM.HelMA.Automata.ETA.OperandParsers
8 import HelVM.HelMA.Automata.ETA.Token
9
10 import HelVM.HelMA.Automaton.Trampoline as Trampoline
11
12 import HelVM.HelMA.Automaton.IO.AutomatonIO
13
14 import HelVM.HelMA.Automaton.Combiner.ALU as Stack
15
16 import Control.Monad.Extra
17 import Control.Type.Operator
18 import HelVM.HelMA.Automata.ETA.Symbol
19
20 import qualified Data.Vector as Vector
21
22 import Prelude hiding (divMod)
23
24 run :: (SAutomatonIO e s m) => Maybe Natural -> Memory s -> m $ Memory s
25 run = trampolineMWithLimit nextState
26
27 nextState :: (SAutomatonIO e s m) => Memory s -> m $ MemorySame s
28 nextState (Memory iu s) = build =<< nextIM iu where build (t , iu') = doInstruction t (Memory iu' s)
29
30 doInstruction :: (SAutomatonIO e s m) => Maybe Token -> Memory s -> m $ MemorySame s
31 -- | IO instructions
32 doInstruction (Just O) u = Trampoline.continue . updateStack u <$> doOutputChar2 (memoryStack u)
33 doInstruction (Just I) u = Trampoline.continue . updateStack u <$> doInputChar2 (memoryStack u)
34
35 -- | Stack instructions
36 doInstruction (Just N) (Memory iu s) = build <$> parseNumber iu where build (symbol , iu') = Trampoline.continue (Memory iu' (push1 symbol s))
37 doInstruction (Just H) u = Trampoline.continue . updateStack u <$> halibut (memoryStack u)
38
39 -- | Arithmetic
40 doInstruction (Just S) u = Trampoline.continue . updateStack u <$> sub (memoryStack u)
41 doInstruction (Just E) u = Trampoline.continue . updateStack u <$> divMod (memoryStack u)
42
43 -- | Control
44 doInstruction (Just R) u = pure $ Trampoline.continue u
45 doInstruction (Just A) (Memory iu@(IM il ic) s) = pure $ Trampoline.continue ((Memory iu . flipPush1 s . genericNextLabel il) ic)
46 doInstruction (Just T) u = transfer u
47 doInstruction Nothing u = end u
48
49 transfer :: (SAutomatonIO e s m) => Memory s -> m $ MemorySame s
50 transfer = branch <=< pop2ForStack where
51 branch (_ , 0 , u) = pure $ Trampoline.continue u
52 branch (0 , _ , u) = end u
53 branch (l , _ , u) = Trampoline.continue . updateAddress u <$> genericFindAddress (memoryProgram u) l
54
55 pop2ForStack :: (SAutomatonIO e s m) => Memory s -> m (e , e , Memory s)
56 pop2ForStack u = build <$> pop2 (memoryStack u) where
57 build (s1 , s2 , s') = (s1 , s2 , updateStack u s')
58
59 -- | Terminate instruction
60 end :: (SAutomatonIO e s m) => Memory s -> m $ MemorySame s
61 end = pure . Trampoline.break
62
63 -- | Memory methods
64
65 newMemory :: TokenList -> s -> Memory s
66 newMemory tl = Memory (IM (Vector.fromList tl) 0)
67
68 updateStack :: Memory s -> s -> Memory s
69 updateStack u s = u {memoryStack = s}
70
71 updateAddress :: Memory s -> InstructionCounter -> Memory s
72 updateAddress u a = u {memoryIM = updatePC (memoryIM u) a}
73
74 memoryProgram :: Memory s -> TokenVector
75 memoryProgram = program . memoryIM
76
77 -- | Types
78
79 type MemorySame s = Same (Memory s)
80
81 data Memory s = Memory
82 { memoryIM :: !InstructionMemory
83 , memoryStack :: s
84 }
85 deriving stock (Eq , Read , Show)