From 06bf4c656377572859846767cb9af5db8fc27893 Mon Sep 17 00:00:00 2001 From: Akshay Date: Fri, 9 Oct 2020 11:35:56 +0530 Subject: use mtl to generate errors --- src/Error.hs | 31 +++++++++++++++++++++++++++++++ src/Evaluator.hs | 22 ++++++++++++++-------- src/Operators.hs | 18 ++++++++++++------ 3 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 src/Error.hs (limited to 'src') diff --git a/src/Error.hs b/src/Error.hs new file mode 100644 index 0000000..276d3e2 --- /dev/null +++ b/src/Error.hs @@ -0,0 +1,31 @@ +module Error ( + LispError (..) + , LispResult (..) + , unwrap + ) where + +import Control.Monad.Except +import Parser +import Text.ParserCombinators.Parsec + +data LispError = Parse ParseError + | BadForm String Expr + | ArgCount Int [Expr] + | UnknownFunction String + | TypeMismatch String Expr + +unwordsList :: [Expr] -> String +unwordsList = unwords . map show + +instance Show LispError where + show (Parse e) = "Parser Error: " ++ show e + show (BadForm s expr) = "Bad Form: " ++ s ++ ": " ++ show expr + show (ArgCount n es) = "Invalid arity, expected " ++ show n ++ ", got values: " ++ unwordsList es + show (UnknownFunction fn) = "Unknown reference to function: " ++ fn + show (TypeMismatch msg got) = "Type mismatch, expected " ++ msg ++ ", got: " ++ show got + +type LispResult = Either LispError + +unwrap :: LispResult t -> t +unwrap (Right v) = v +unwrap (Left _) = undefined -- should panic diff --git a/src/Evaluator.hs b/src/Evaluator.hs index f264ee0..28ee79b 100644 --- a/src/Evaluator.hs +++ b/src/Evaluator.hs @@ -2,21 +2,27 @@ module Evaluator ( eval ) where +import Control.Monad.Except +import Error (LispError (..), LispResult (..), + unwrap) import Operators import Parser import Text.ParserCombinators.Parsec -apply :: String -> [Expr] -> Expr +apply :: String -> [Expr] -> LispResult Expr apply fn args = case lookup fn primitives of Just f -> f args - _ -> BoolLiteral False -- TODO: error out instead + _ -> throwError $ UnknownFunction fn -eval :: Expr -> Expr -eval v@(StringLiteral s) = v -eval v@(IntLiteral i) = v -eval v@(BoolLiteral b) = v +eval :: Expr -> LispResult Expr +eval v@(StringLiteral s) = return v +eval v@(IntLiteral i) = return v +eval v@(BoolLiteral b) = return v -- handle quotes as literals -eval (List[Id "quote", val]) = val -eval (List (Id fn : args)) = apply fn $ map eval args +eval (List[Id "quote", val]) = return val +eval (List (Id fn : args)) = mapM eval args >>= apply fn + +-- handle bad forms +eval idk = throwError $ BadForm "lisk can't recognize this form" idk diff --git a/src/Operators.hs b/src/Operators.hs index e57f885..3b96281 100644 --- a/src/Operators.hs +++ b/src/Operators.hs @@ -2,9 +2,11 @@ module Operators ( primitives ) where +import Control.Monad.Except +import Error (LispError (..), LispResult (..)) import Parser -primitives :: [(String, [Expr] -> Expr)] +primitives :: [(String, [Expr] -> LispResult Expr)] primitives = [ ("+", arithmetic (+)) @@ -13,10 +15,14 @@ primitives = , ("/", arithmetic div) ] -arithmetic :: (Integer -> Integer -> Integer) -> [Expr] -> Expr -arithmetic op args = IntLiteral $ foldl1 op $ map unwrapNum args +arithmetic :: (Integer -> Integer -> Integer) -> [Expr] -> LispResult Expr +arithmetic op args + | length args < 2 = throwError $ ArgCount 2 args + | otherwise = do + as <- mapM unwrapNum args + return . IntLiteral $ foldl1 op as -unwrapNum :: Expr -> Integer -unwrapNum (IntLiteral n) = n -unwrapNum _ = undefined +unwrapNum :: Expr -> LispResult Integer +unwrapNum (IntLiteral n) = return n +unwrapNum x = throwError $ TypeMismatch "number" x -- cgit v1.2.3