/
StackImpl.hs
121 lines (95 loc) 路 2.77 KB
/
StackImpl.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
{-#LANGUAGE UndecidableInstances#-}
module HelVM.HelMA.Common.Memories.StackImpl (
Index,
Stack,
divMod,
sub,
binaryOp,
binaryOps,
halibut,
move,
swap,
discard,
slide,
dup,
copy,
pushChar1,
genericPush1,
push1,
push2,
empty,
lookup,
splitAt,
drop,
pop1,
pop2
) where
import HelVM.HelMA.Common.BinaryOperator
import Prelude hiding (divMod , drop , empty , fromList , splitAt , swap)
import qualified HelVM.HelMA.Common.Collections.Drop as I
import qualified HelVM.HelMA.Common.Collections.FromList as I
import qualified HelVM.HelMA.Common.Collections.Lookup as I
import qualified HelVM.HelMA.Common.Collections.Pop as I
import qualified HelVM.HelMA.Common.Collections.SplitAt as I
type Index = Int
-- Arithmetic
divMod :: (Integral e , Stack e c) => c -> c
divMod = binaryOps [Mod , Div]
sub :: (Integral e , Stack e c) => c -> c
sub = binaryOp Sub
binaryOp :: (Integral e , Stack e c) => BinaryOperator -> c -> c
binaryOp op = binaryOps [op]
binaryOps :: (Integral e , Stack e c) => [BinaryOperator] -> c -> c
binaryOps ops c = pushList (calculateOps e e' ops) c' where (e , e', c') = pop2 c
-- Stack instructions
halibut :: (Integral e , Stack e c) => c -> c
halibut c
| i <= 0 = copy (negate i) c'
| otherwise = move i c'
where
i = fromIntegral e
(e , c') = pop1 c
move :: Stack e c => Index -> c -> c
move i c = c1 <> c2 <> c3 where
(c1 , c3) = splitAt 1 c'
(c2 , c') = splitAt i c
swap :: Stack e c => c -> c
swap c = push2 e' e c' where (e , e', c') = pop2 c
discard :: Stack e c => c -> c
discard = drop 1
slide :: Stack e c => Index -> c -> c
slide i c = push1 e (drop i c') where (e , c') = pop1 c
dup :: Stack e c => c -> c
dup = copy 0
copy :: Stack e c => Index -> c -> c
copy i c = push1 (c `index` i) c
-- Push instructions
pushChar1 :: (Num e , Stack e c) => Char -> c -> c
pushChar1 = genericPush1 . ord
genericPush1 :: (Integral v , Num e , Stack e c) => v -> c -> c
genericPush1 = push1 . fromIntegral
push1 :: Stack e c => e -> c -> c
push1 e = pushList [e]
push2 :: Stack e c => e -> e -> c -> c
push2 e e' = pushList [e , e']
pushList :: Stack e c => [e] -> c -> c
pushList es c = fromList es <> c
----
class (Semigroup c , Show c) => Stack e c | c -> e where
fromList :: [e] -> c
empty :: c
index :: c -> Index -> e
lookup :: Index -> c -> Maybe e
splitAt :: Index -> c -> (c , c)
drop :: Index -> c -> c
pop1 :: c -> (e , c)
pop2 :: c -> (e , e , c)
instance (Show c , Semigroup c , I.Drop e c , I.FromList e c , I.Lookup e c , I.SplitAt e c , I.Pop1 e c , I.Pop2 e c) => Stack e c where
fromList = I.fromList
empty = I.empty
index = I.index
lookup = I.lookup
splitAt = I.splitAt
drop = I.drop
pop1 = I.pop1
pop2 = I.pop2