-
Notifications
You must be signed in to change notification settings - Fork 1
/
hexsp.hs
301 lines (273 loc) · 7.6 KB
/
hexsp.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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
import Data.ByteString as BS
import Data.Char as Char
import Data.Function
import Data.List as List
import Data.Map as Map
import Data.Maybe as Maybe
import Data.Text as Text
import Control.Monad
import Control.Monad.State
import Numeric (readHex)
import System.Environment (getArgs)
import System.IO as IO
import Text.Parsec
import Text.Parsec.String
import Text.Printf
data Expr = Pair (Expr, Expr) | Nil | Symbol Integer | Number Integer deriving (Eq)
--instance Show Expr where
-- show (Nil) = "Nil"
-- show (Symbol x) = "Symbol " ++ showHex x
-- show (Number x)
-- | x < 0 = "Number -" ++ showHex (negate x)
-- | otherwise = "Number " ++ showHex x
-- show p@(Pair (x, y))
-- | isList p = "(" ++ ((List.concat).(List.intersperse ", ").(List.map show).pairsToList $ p) ++ ")"
-- | otherwise = "(" ++ show x ++ ", " ++ show y ++ ")"
instance Show Expr where
show (Nil) = "EE 33 "
show (Symbol x) = showHex x ++ " "
show (Number x)
| x < 0 = "22 " ++ showHex (negate x) ++ " "
| otherwise = "55 " ++ showHex x ++ " "
show p@(Pair (x, y))
| isList p = "EE " ++ ((List.concat).(List.map show).pairsToList $ p) ++ "33 "
| otherwise = "EE " ++ show x ++ "11 " ++ show y ++ "33 "
type Env = Map Integer Object
data Object = Expr Expr | Closure Expr Env deriving (Show)
lookupEnv _ [] = Nothing
lookupEnv k env = listToMaybe $ Maybe.mapMaybe (Map.lookup k) [List.head env, List.last env]
keywords = ["00", "11", "22", "EE", "33", "55", "99", "FF"]
hexs = let h = ['0'..'9'] ++ ['A'..'F'] in [[x, y] | x <- h, y <- h]
showHex :: Integer -> String
showHex i = do
let s = printf "%X" i
let a = if even $ List.length s then s else '0':s
Text.unpack $ Text.concat $ List.intersperse (Text.pack " ") $ chunksOf 2 (Text.pack a)
isPair :: Expr -> Bool
isPair (Pair _) = True
isPair _ = False
isNil :: Expr -> Bool
isNil e = e == Nil
isList :: Expr -> Bool
isList (Pair (_, Nil)) = True
isList (Pair (_, Pair (x, y))) = isList $ Pair (x, y)
isList (Pair (_, _)) = False
listToPairs :: [Expr] -> Expr
listToPairs [] = Nil
listToPairs (x:xs) = Pair (x, listToPairs xs)
pairsToList :: Expr -> [Expr]
pairsToList (Pair (x, Nil)) = [x]
pairsToList (Pair (x, y)) = x:(pairsToList y)
pairsToList _ = error "invalid pairs"
expr :: Parser Expr
expr = do
zeroSpaces
a <- try list <|> try pair <|> try nil <|> try quote <|> try symbol <|> try number
zeroSpaces
return a
zeroSpaces :: Parser ()
zeroSpaces = do
many.try.string $ "00 "
return ()
list :: Parser Expr
list = do
string "EE "
x <- many1 expr
string "33 "
return $ listToPairs x
pair :: Parser Expr
pair = do
string "EE "
x <- expr
string "11 "
y <- expr
string "33 "
return $ Pair (x, y)
nil :: Parser Expr
nil = do
string "EE "
string "33 "
return $ Nil
quote :: Parser Expr
quote = do
string "99 "
a <- expr
return $ listToPairs [Symbol 0x9207E0, a]
number :: Parser Expr
number = do
sign <- (try $ string "55 " >> return id) <|> (try $ string "22 " >> return negate)
a <- hexList
return $ Number $ sign a
symbol :: Parser Expr
symbol = do
a <- hexList
return $ Symbol a
hexList :: Parser Integer
hexList = do
xs <- many1 (try escape <|> try normal)
return $ fst.(List.head).readHex.(List.concat) $ xs
where
escape = do
string "FF "
let l = List.map (try.string) keywords
x <- List.foldl (<|>) (List.head l) (List.tail l)
space
return x
normal = do
let l = List.map (try.string) $ hexs List.\\ keywords
x <- List.foldl (<|>) (List.head l) (List.tail l)
space
return x
eval :: Expr -> StateT [Env] IO Expr
--nil
eval Nil = do
return Nil
--number
eval (Number x) = do
return $ Number x
--if
eval (Pair (Symbol 0x1F, Pair (c, Pair (x, Pair (y, Nil))))) = do
c <- eval c
if c == Nil then eval y else eval x
--eq
eval (Pair (Symbol 0xE9, Pair (x, Pair (y, Nil)))) = do
x <- eval x
y <- eval y
return $ if x == y then Symbol 0x77 else Nil
--quote
eval (Pair (Symbol 0x9207E0, Pair (x, Nil))) = do
return x
--atom
eval (Pair (Symbol 0xA703, Pair (x, Nil))) = do
x <- eval x
return $ case x of
Pair (_, _) -> Nil
_ -> Symbol 0x77
--car
eval (Pair (Symbol 0xCA70, Pair (x, Nil))) = do
Pair (a, b) <- eval x
return a
--cdr
eval (Pair (Symbol 0xCD70, Pair (x, Nil))) = do
Pair (a, b) <- eval x
return b
--cons
eval (Pair (Symbol 0xC025, Pair (x, Pair (y , Nil)))) = do
x <- eval x
y <- eval y
return $ Pair (x, y)
--add
eval (Pair (Symbol 0xADD0, Pair (x, Pair (y , Nil)))) = do
(Number x) <- eval x
(Number y) <- eval y
return $ Number $ x + y
--sub
eval (Pair (Symbol 0x52B0, Pair (x, Pair (y , Nil)))) = do
(Number x) <- eval x
(Number y) <- eval y
return $ Number $ x - y
--begin
eval (Pair (Symbol 0xBE9120, Pair (x, Nil))) = do
let prog = pairsToList x
v <- mapM eval prog
return $ List.last v
--write
eval (Pair (Symbol 0x3717E0, Pair (x, Nil))) = do
v <- eval x
lift $ print v
return v
--setq
eval (Pair (Symbol 0x5E79, Pair (Symbol x, Pair (y , Nil)))) = do
v <- eval y
(e:es) <- get
put $ (Map.insert x (Expr v) e):es
return v
--defunc
eval (Pair (Symbol 0xDEF22C, Pair (Symbol s, Pair (x, Pair (y, Nil))))) = do
let f = listToPairs [Symbol 0xF22C, x, y]
(e:es) <- get
put $ (Map.insert s (Expr f) e):es
return f
--exec func
eval (Pair (Symbol f, x)) = do
env <- get
(param, prog) <- case (lookupEnv f env) of
Just (Expr (Pair (Symbol 0xF22C, Pair (param, Pair (prog, Nil))))) -> return (param, prog)
_ -> lift $ error "error invalid func"
ex <- mapM eval $ pairsToList x
let arg = List.map Expr ex
let prm = List.map symbolToInteger $ pairsToList param
funcEnv <- if List.length prm == List.length arg
then return $ fromList $ List.zip prm arg
else lift $ error "invalid arg"
put $ funcEnv:env
v <- eval prog
modify List.tail
return v
where
symbolToInteger (Symbol s) = s
symbolToInteger _ = undefined
--symbol
eval (Symbol x) = do
env <- get
case (lookupEnv x env) of
Just (Expr v) -> return v
_ -> lift $ error $ "error invalid symbol " ++ show (Symbol x)
--otherwise
eval expr = do
lift $ error $ "error: " ++ show expr
return Nil
--TODO lambda read
keywordEnv = fromList $ do
{
[
(0x77, Expr $ Symbol 0x77),
envTuple 0xCA70 1,
envTuple 0xCD70 1,
envTuple 0xA703 1,
envTuple 0x9207E0 1,
envTuple 0x3717E0 1,
envTuple 0xBE9120 1,
envTuple 0xC025 2,
envTuple 0xE9 2,
envTuple 0xADD0 2,
envTuple 0x52B0 2,
envTuple 0x5E79 2,
envTuple 0x1F 3,
envTuple 0xDEF22C 3
]
}
where
envTuple s n = (s, genFunc s n)
genFunc s n = Expr $ listToPairs $ [Symbol 0xF22C, listToPairs $ List.map Symbol [1..n], listToPairs $ List.map Symbol (s:[1..n])]
repl env = do
IO.putStr "hexsp> "
b <- IO.getLine
let bb = Text.unpack $ Text.concat $ List.intersperse (Text.pack " ") $ chunksOf 2 $ Text.map Char.toUpper $ Text.filter (/= ' ') $ Text.pack b
if List.null bb then repl env else return ()
let e = parse (many expr) "" $ bb ++ " "
case e of
Right x -> repl.snd =<< f x env
Left y -> print y >> repl env
where
f [] env = print "parse error" >> return (Nil, env)
f (x:[]) env = do
(a, s) <- runStateT (eval x) env
print a
return (a, s)
f (x:xs) env = do
(a, s) <- runStateT (eval x) env
print a
f xs s
main = do
args <- getArgs
if List.null args then repl [keywordEnv] else return ()
a <- BS.readFile $ List.head args
let b = List.concat $ List.map (\i -> printf "%02X " i) $ BS.unpack $ a :: String
let e = parse (many expr) "" b
case e of
Right x -> f x [keywordEnv] >> return ()
Left y -> print y
where
f (x:[]) s = runStateT (eval x) s
f (x:xs) s = (f xs) =<< execStateT (eval x) s