Skip to content

Commit

Permalink
Working REPL
Browse files Browse the repository at this point in the history
  • Loading branch information
abedra committed Apr 7, 2012
1 parent b51a197 commit de74bfe
Showing 1 changed file with 56 additions and 32 deletions.
88 changes: 56 additions & 32 deletions valence.hs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Main where
import System.Environment import System.Environment
import Control.Monad import Control.Monad
import Control.Monad.Error import Control.Monad.Error
import IO hiding (try)
import Text.ParserCombinators.Parsec hiding (spaces) import Text.ParserCombinators.Parsec hiding (spaces)


data LispVal = Atom String data LispVal = Atom String
Expand All @@ -22,34 +23,6 @@ data LispError = NumArgs Integer [LispVal]
symbol :: Parser Char symbol :: Parser Char
symbol = oneOf "#!$%&|*+-/:<=>?@^_-" symbol = oneOf "#!$%&|*+-/:<=>?@^_-"


primitives :: [(String, [LispVal] -> ThrowsError LispVal)]
primitives = [("+", operator (+)),
("-", operator (-)),
("*", operator (*)),
("/", operator div),
("mod", operator mod),
("quotient", operator quot),
("remainder", operator rem),
("=", numBoolBinop (==)),
("<", numBoolBinop (<)),
(">", numBoolBinop (>)),
("/=", numBoolBinop (/=)),
(">=", numBoolBinop (>=)),
("<=", numBoolBinop (<=)),
("&&", boolBoolBinop (&&)),
("||", boolBoolBinop (||)),
("string=?", strBoolBinop (==)),
("string<?", strBoolBinop (<)),
("string>?", strBoolBinop (>)),
("string<=?", strBoolBinop (<=)),
("string>=?", strBoolBinop (>=)),
("car", car),
("cdr", cdr),
("cons", cons),
("eq?", eqv),
("eqv?", eqv),
("equal?", equal)]

operator :: (Integer -> Integer -> Integer) -> [LispVal] -> ThrowsError LispVal operator :: (Integer -> Integer -> Integer) -> [LispVal] -> ThrowsError LispVal
operator op singleVal@[_] = throwError $ NumArgs 2 singleVal operator op singleVal@[_] = throwError $ NumArgs 2 singleVal
operator op params = mapM unpackNum params >>= return . Number . foldl1 op operator op params = mapM unpackNum params >>= return . Number . foldl1 op
Expand Down Expand Up @@ -179,6 +152,34 @@ equal [arg1, arg2] = do
return $ Bool $ (primitiveEquals || let (Bool x) = eqvEquals in x) return $ Bool $ (primitiveEquals || let (Bool x) = eqvEquals in x)
equal badArgList = throwError $ NumArgs 2 badArgList equal badArgList = throwError $ NumArgs 2 badArgList


primitives :: [(String, [LispVal] -> ThrowsError LispVal)]
primitives = [("+", operator (+)),
("-", operator (-)),
("*", operator (*)),
("/", operator div),
("mod", operator mod),
("quotient", operator quot),
("remainder", operator rem),
("=", numBoolBinop (==)),
("<", numBoolBinop (<)),
(">", numBoolBinop (>)),
("/=", numBoolBinop (/=)),
(">=", numBoolBinop (>=)),
("<=", numBoolBinop (<=)),
("&&", boolBoolBinop (&&)),
("||", boolBoolBinop (||)),
("string=?", strBoolBinop (==)),
("string<?", strBoolBinop (<)),
("string>?", strBoolBinop (>)),
("string<=?", strBoolBinop (<=)),
("string>=?", strBoolBinop (>=)),
("car", car),
("cdr", cdr),
("cons", cons),
("eq?", eqv),
("eqv?", eqv),
("equal?", equal)]

instance Show LispVal where show = showVal instance Show LispVal where show = showVal
unwordsList :: [LispVal] -> String unwordsList :: [LispVal] -> String
unwordsList = unwords . map showVal unwordsList = unwords . map showVal
Expand Down Expand Up @@ -208,6 +209,28 @@ showError (NumArgs expected found) = "Expected " ++ show expected ++ " arguments
showError (TypeMismatch expected found) = "Invalid type: expected " ++ expected ++ ", found " ++ show found showError (TypeMismatch expected found) = "Invalid type: expected " ++ expected ++ ", found " ++ show found
showError (Parser parseErr) = "Parse error at " ++ show parseErr showError (Parser parseErr) = "Parse error at " ++ show parseErr


flushStr :: String -> IO ()
flushStr str = putStr str >> hFlush stdout

readPrompt :: String -> IO String
readPrompt prompt = flushStr prompt >> getLine

evalString :: String -> IO String
evalString expr = return $ extractValue $ trapError (liftM show $ readExpr expr >>= eval)

evalAndPrint :: String -> IO ()
evalAndPrint expr = evalString expr >>= putStrLn

until_ :: Monad m => (a -> Bool) -> m a -> (a -> m ()) -> m ()
until_ pred prompt action = do
result <- prompt
if pred result
then return ()
else action result >> until_ pred prompt action

runRepl :: IO ()
runRepl = until_ (== "quit") (readPrompt "Valence>> ") evalAndPrint

readExpr :: String -> ThrowsError LispVal readExpr :: String -> ThrowsError LispVal
readExpr input = case parse parseExpr "lisp" input of readExpr input = case parse parseExpr "lisp" input of
Left err -> throwError $ Parser err Left err -> throwError $ Parser err
Expand All @@ -232,7 +255,8 @@ eval (List (Atom func : args)) = mapM eval args >>= apply func
eval badForm = throwError $ BadSpecialForm "Unrecognized special form" badForm eval badForm = throwError $ BadSpecialForm "Unrecognized special form" badForm


main :: IO () main :: IO ()
main = do main = do args <- getArgs
args <- getArgs case length args of
evaled <- return $ liftM show $ readExpr (args !! 0) >>= eval 0 -> runRepl
putStrLn $ extractValue $ trapError evaled 1 -> evalAndPrint $ args !! 0
otherwise -> putStrLn "Program takes only 0 or 1 arguments"

0 comments on commit de74bfe

Please sign in to comment.