@@ -18,11 +18,11 @@ import LeespTypes
18
18
import LeespParser
19
19
20
20
main :: IO ()
21
- main = do args <- getArgs
22
- case length args of
23
- 0 -> runRepl
24
- 1 -> runOne $ head args
25
- _ -> putStrLn " Program takes only 0 or 1 argument "
21
+ main = do
22
+ args <- getArgs
23
+ if null args
24
+ then runRepl
25
+ else runOne $ args
26
26
27
27
-- REPL FUNS
28
28
flushStr :: String -> IO ()
@@ -33,7 +33,6 @@ readPrompt prompt = flushStr prompt >> getLine
33
33
34
34
evalString :: Env -> String -> IO String
35
35
evalString env expr = runIOThrows $ liftM show $ (liftThrows $ readExpr expr) >>= eval env
36
- -- evalString expr = return $ extractValue $ trapError (liftM show $ readExpr expr >>= eval)
37
36
38
37
evalAndPrint :: Env -> String -> IO ()
39
38
evalAndPrint env expr = evalString env expr >>= putStrLn
@@ -42,33 +41,39 @@ until_ :: Monad m => (a -> Bool) -> m a -> (a -> m ()) -> m ()
42
41
until_ pred prompt action = do
43
42
result <- prompt
44
43
unless (pred result) $ action result >> until_ pred prompt action
45
- -- if pred result
46
- -- then return ()
47
- -- else action result >> until_ pred prompt action
48
-
49
- -- runOne :: String -> IO ()
50
- -- runOne expr = nullEnv >>= flip evalAndPrint expr
51
-
52
- -- runRepl :: IO ()
53
- -- runRepl = nullEnv >>= until_ (== "quit") (readPrompt "Leesp >> ") . evalAndPrint
54
44
45
+ {- This version runs a single input command from stdin
55
46
runOne :: String -> IO ()
56
47
runOne expr = primitiveBindings >>= flip evalAndPrint expr
48
+ -}
49
+
50
+ -- This version of runOne expects a file input to read from.
51
+ runOne :: [String ] -> IO ()
52
+ runOne args = do
53
+ env <- primitiveBindings >>= flip bindVars [(" args" , List $ map String $ drop 1 args)]
54
+ (runIOThrows $ liftM show
55
+ $ eval env (List [Atom " load" , String (head args)])) >>= hPutStrLn stderr
57
56
58
57
runRepl :: IO ()
59
58
runRepl = primitiveBindings >>= until_ (== " quit" ) (readPrompt " Leesp >> " ) . evalAndPrint
60
59
61
60
-- END REPL FUNS
62
61
63
- readExpr :: String -> ThrowsError LispVal
64
- readExpr input = case parse parseExpr " lisp " input of
65
- Left err -> throwError $ Parser err
62
+ readOrThrow :: Parser a -> String -> ThrowsError a
63
+ readOrThrow parser input = case parse parser " leesp " input of
64
+ Left err -> throwError $ Parser err
66
65
Right val -> return val
67
66
68
- -- apply :: String -> [LispVal] -> ThrowsError LispVal
69
- -- apply func args = maybe (throwError $ NotFunction "Unrecognised primitive function args" func)
70
- -- ($ args)
71
- -- (lookup func primitives)
67
+ readExpr :: String -> ThrowsError LispVal
68
+ readExpr = readOrThrow parseExpr
69
+
70
+ readExprList :: String -> ThrowsError [LispVal ]
71
+ readExprList = readOrThrow (endBy parseExpr spaces)
72
+
73
+ -- readExpr :: String -> ThrowsError LispVal
74
+ -- readExpr input = case parse parseExpr "lisp" input of
75
+ -- Left err -> throwError $ Parser err
76
+ -- Right val -> return val
72
77
73
78
apply :: LispVal -> [LispVal ] -> IOThrowsError LispVal
74
79
apply (PrimitiveFunc func) args = liftThrows $ func args
@@ -92,6 +97,9 @@ eval env val@(Bool _) = return val
92
97
eval env val@ (Character _) = return val
93
98
eval env val@ (Keyword _) = return val
94
99
eval env (Atom id ) = getVar env id
100
+ -- Load a file and eval the contents
101
+ eval env (List [Atom " load" , String filename]) =
102
+ load filename >>= liftM last . mapM (eval env)
95
103
-- Handled Quoting.
96
104
eval env (List [Atom " quote" , val]) = return val
97
105
-- Flow Control Functions.
@@ -188,6 +196,17 @@ primitives = [("+", numericBinop (+)),
188
196
(" string-insert!" , stringinsertFn),
189
197
(" substring" , subStringFn)]
190
198
199
+ ioPrimitives :: [(String , [LispVal ] -> IOThrowsError LispVal )]
200
+ ioPrimitives = [(" apply" , applyProc),
201
+ (" open-input-file" , makePort ReadMode ),
202
+ (" open-output-file" , makePort WriteMode ),
203
+ (" close-input-port" , closePort),
204
+ (" close-output-port" , closePort),
205
+ (" read" , readProc),
206
+ (" write" , writeProc),
207
+ (" read-contents" , readContents),
208
+ (" read-all" , readAll)]
209
+
191
210
subStringFn :: [LispVal ] -> ThrowsError LispVal
192
211
subStringFn [String s, Number start, Number end]
193
212
| indicesValid = (return . String ) $ genericSubList s
@@ -322,9 +341,13 @@ equal badArgList = throwError $ NumArgs 2 badArgList
322
341
nullEnv :: IO Env
323
342
nullEnv = newIORef []
324
343
344
+ makeFunc :: Monad m => Maybe String -> Env -> [LispVal ] -> [LispVal ] -> m LispVal
325
345
makeFunc varargs env params body = return $ Func (map showVal params) varargs body env
326
346
347
+ makeNormalFunc :: Env -> [LispVal ] -> [LispVal ] -> ErrorT LispError IO LispVal
327
348
makeNormalFunc = makeFunc Nothing
349
+
350
+ makeVarargs :: LispVal -> Env -> [LispVal ] -> [LispVal ] -> ErrorT LispError IO LispVal
328
351
makeVarargs = makeFunc . Just . showVal
329
352
330
353
liftThrows :: ThrowsError a -> IOThrowsError a
@@ -373,6 +396,36 @@ bindVars envRef bindings = readIORef envRef >>= extendEnv bindings >>= newIORef
373
396
return (var, ref)
374
397
375
398
primitiveBindings :: IO Env
376
- primitiveBindings = nullEnv >>= (flip bindVars $ map makePrimitiveFunc primitives)
399
+ primitiveBindings = nullEnv >>= (flip bindVars $ map (makeFunc IOFunc ) ioPrimitives
400
+ ++ map (makeFunc PrimitiveFunc ) primitives)
377
401
where
378
- makePrimitiveFunc (var, func) = (var, PrimitiveFunc func)
402
+ makeFunc constructor (var, func) = (var, constructor func)
403
+
404
+ -- START IO PRIMITIVES
405
+ applyProc :: [LispVal ] -> IOThrowsError LispVal
406
+ applyProc [func, List args] = apply func args
407
+ applyProc (func : args) = apply func args
408
+
409
+ makePort :: IOMode -> [LispVal ] -> IOThrowsError LispVal
410
+ makePort mode [String filename] = liftM Port $ liftIO $ openFile filename mode
411
+
412
+ closePort :: [LispVal ] -> IOThrowsError LispVal
413
+ closePort [Port port] = liftIO $ hClose port >> (return $ Bool True )
414
+
415
+ readProc :: [LispVal ] -> IOThrowsError LispVal
416
+ readProc [] = readProc [Port stdin]
417
+ readProc [Port port] = (liftIO $ hGetLine port) >>= liftThrows . readExpr
418
+
419
+ writeProc :: [LispVal ] -> IOThrowsError LispVal
420
+ writeProc [obj] = writeProc [obj, Port stdout]
421
+ writeProc [obj, Port port] = liftIO $ hPrint port obj >> (return $ Bool True )
422
+
423
+ readContents :: [LispVal ] -> IOThrowsError LispVal
424
+ readContents [String filename] = liftM String $ liftIO $ readFile filename
425
+
426
+ load :: String -> IOThrowsError [LispVal ]
427
+ load filename = (liftIO $ readFile filename) >>= liftThrows . readExprList
428
+
429
+ readAll :: [LispVal ] -> IOThrowsError LispVal
430
+ readAll [String filename] = liftM List $ load filename
431
+ -- END IO PRIMITIVES
0 commit comments