aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAkshay <[email protected]>2020-10-16 14:24:46 +0100
committerAkshay <[email protected]>2020-10-16 14:24:46 +0100
commitb19a4a35db4cd951c52e179f3340518c9e2dcc1e (patch)
tree6d3d840a995d0467577ca645f5838a16d78aa3d6 /src
parent684e09298b8453ee56571d8a225e11d7c57e3746 (diff)
add initial support for variable definition
Diffstat (limited to 'src')
-rw-r--r--src/Environment.hs69
-rw-r--r--src/Error/Base.hs24
-rw-r--r--src/Error/Pretty.hs9
-rw-r--r--src/Evaluator.hs38
-rw-r--r--src/Operators.hs4
-rw-r--r--src/Parser.hs2
6 files changed, 113 insertions, 33 deletions
diff --git a/src/Environment.hs b/src/Environment.hs
new file mode 100644
index 0000000..7b3f365
--- /dev/null
+++ b/src/Environment.hs
@@ -0,0 +1,69 @@
1module Environment ( Env
2 , setVar
3 , getVar
4 , defineVar
5 , manyBindings
6 , newEnv
7 , liftLispResult
8 , IOResult
9 ) where
10
11import Control.Monad (liftM, mapM)
12import Control.Monad.Except
13import Data.IORef
14import Data.Maybe (isJust)
15import Error.Base (LispError (..), LispResult (..), unwrap)
16import Parser (Expr (..))
17
18type Env = IORef [(String, IORef Expr)]
19
20newEnv :: IO Env
21newEnv = newIORef []
22
23type IOResult = ExceptT LispError IO
24
25liftLispResult :: LispResult a -> IOResult a
26liftLispResult (Left err) = throwError err
27liftLispResult (Right val) = return val
28
29isBound :: Env -> String -> IO Bool
30isBound env var = do
31 ptr <- readIORef env
32 return $ isJust $ lookup var ptr
33
34-- env modifiers
35
36getVar :: Env -> String -> IOResult Expr
37getVar env var = do
38 ptr <- liftIO $ readIORef env
39 maybe (throwError $ UnboundVariable var)
40 (liftIO . readIORef)
41 $ lookup var ptr
42
43setVar :: Env -> String -> Expr -> IOResult ()
44setVar env var val = do
45 ptr <- liftIO $ readIORef env
46 maybe (throwError $ UnboundVariable var)
47 (liftIO . (flip writeIORef val))
48 $ lookup var ptr
49
50defineVar :: Env -> String -> Expr -> IOResult ()
51defineVar env var val = do
52 alreadyBound <- liftIO $ isBound env var
53 if alreadyBound
54 then setVar env var val
55 else liftIO $ do
56 newRef <- newIORef val
57 ptr <- readIORef env
58 writeIORef env $ (var, newRef):ptr
59
60makeBind :: (String, Expr) -> IO (String, IORef Expr)
61makeBind (var, val) = do
62 n <- newIORef val
63 return (var, n)
64
65manyBindings :: Env -> [(String, Expr)] -> IO Env
66manyBindings env binds = do
67 ptr <- readIORef env
68 extendedEnv <- liftM (++ ptr) $ mapM makeBind binds
69 newIORef extendedEnv
diff --git a/src/Error/Base.hs b/src/Error/Base.hs
index d7b685c..ef32d52 100644
--- a/src/Error/Base.hs
+++ b/src/Error/Base.hs
@@ -1,8 +1,7 @@
1module Error.Base ( 1module Error.Base ( LispError (..)
2 LispError (..) 2 , LispResult (..)
3 , LispResult (..) 3 , unwrap
4 , unwrap 4 ) where
5 ) where
6 5
7import Control.Monad.Except 6import Control.Monad.Except
8import Parser 7import Parser
@@ -15,19 +14,24 @@ data LispError = Parse ParseError
15 | ArgCount String Int [Expr] 14 | ArgCount String Int [Expr]
16 | UnknownFunction String 15 | UnknownFunction String
17 | TypeMismatch String Expr 16 | TypeMismatch String Expr
17 | UnboundVariable String
18 18
19unwordsList :: [Expr] -> String 19unwordsList :: [Expr] -> String
20unwordsList = unwords . map show 20unwordsList = unwords . map show
21 21
22literal :: String -> String
23literal v = "`" <> v <> "`"
24
22instance Show LispError where 25instance Show LispError where
23 show (Parse e) = "Parser Error: " ++ show e 26 show (Parse e) = "Parser Error: " ++ show e
24 show (BadForm s expr) = "Bad Form: " ++ s ++ ": " ++ show expr 27 show (BadForm s expr) = "Bad Form: " ++ literal s ++ ": " ++ show expr
25 -- TODO: clean this up 28 -- TODO: clean this up
26 show (ArgCount fn n es) 29 show (ArgCount fn n es)
27 | null es = "Invalid arity, `" ++ fn ++ "` expects " ++ show n ++ " or more expression(s)!" 30 | null es = "Invalid arity, " ++ literal fn ++ " expects " ++ show n ++ " or more expression(s)!"
28 | otherwise = "Invalid arity, `" ++ fn ++ "` expects " ++ show n ++ " or more expression(s), got value(s): " ++ unwordsList es 31 | otherwise = "Invalid arity, " ++ literal fn ++ " expects " ++ show n ++ " or more expression(s), got value(s): " ++ unwordsList es
29 show (UnknownFunction fn) = "Cannot apply function: " ++ fn 32 show (UnknownFunction fn) = "Cannot apply function: " ++ literal fn
30 show (TypeMismatch msg got) = "Type mismatch, expected " ++ msg ++ ", got: " ++ show got 33 show (TypeMismatch msg got) = "Type mismatch, expected " ++ literal msg ++ ", got: " ++ show got
34 show (UnboundVariable name) = "Possibly unbound variable: " ++ literal name
31 35
32type LispResult = Either LispError 36type LispResult = Either LispError
33 37
diff --git a/src/Error/Pretty.hs b/src/Error/Pretty.hs
index 44601d6..a90131b 100644
--- a/src/Error/Pretty.hs
+++ b/src/Error/Pretty.hs
@@ -1,8 +1,7 @@
1module Error.Pretty ( 1module Error.Pretty ( showError
2 showError 2 , Options (..)
3 , Options (..) 3 , defaults
4 , defaults 4 ) where
5 ) where
6 5
7import Data.List (intercalate, nub) 6import Data.List (intercalate, nub)
8import Error.Base (LispError (..)) 7import Error.Base (LispError (..))
diff --git a/src/Evaluator.hs b/src/Evaluator.hs
index 8a5274f..e3bf697 100644
--- a/src/Evaluator.hs
+++ b/src/Evaluator.hs
@@ -1,8 +1,7 @@
1module Evaluator ( 1module Evaluator (eval) where
2 eval
3 ) where
4 2
5import Control.Monad.Except 3import Control.Monad.Except
4import Environment
6import Error.Base (LispError (..), LispResult (..), 5import Error.Base (LispError (..), LispResult (..),
7 unwrap) 6 unwrap)
8import Operators 7import Operators
@@ -15,18 +14,27 @@ apply fn args = maybe
15 ($ args) 14 ($ args)
16 (lookup fn primitives) 15 (lookup fn primitives)
17 16
18eval :: Expr -> LispResult Expr 17eval :: Env -> Expr -> IOResult Expr
19eval v@(StringLiteral s) = return v 18eval _ v@(StringLiteral s) = return v
20eval v@(IntLiteral i) = return v 19eval _ v@(IntLiteral i) = return v
21eval v@(BoolLiteral b) = return v 20eval _ v@(BoolLiteral b) = return v
22eval v@(FloatLiteral f) = return v 21eval env (Id l) = getVar env l
23eval v@(Vector xs) = liftM Vector $ mapM eval xs 22eval _ v@(FloatLiteral f) = return v
24-- handle quotes as literals 23eval env v@(Vector xs) = liftM Vector $ mapM (eval env) xs
25eval (List[Id "quote", val]) = return val 24eval env (List[Id "quote", val]) = return val
26eval (List[Id "quasiquote", val]) = undefined 25eval env (List[Id "quasiquote", val]) = undefined
27eval (List[Id "unquote", val]) = undefined 26eval env (List[Id "unquote", val]) = eval env val
28eval (List (Id fn : args)) = mapM eval args >>= apply fn 27eval env (List [Id "set!", Id var, val]) = do
28 e <- eval env val
29 setVar env var e
30 return e
31eval env (List [Id "define", Id var, val]) = do
32 e <- eval env val
33 defineVar env var e
34 return e
35eval env (List (Id fn : args)) = mapM (eval env) args >>= liftLispResult . apply fn
36eval env NoReturn = throwError $ BadForm "Invalid usage of non-returning expression" NoReturn
29 37
30-- handle bad forms 38-- handle bad forms
31eval invalidForm = throwError $ BadForm "lisk can't recognize this form" invalidForm 39eval env invalidForm = throwError $ BadForm "lisk can't recognize this form" invalidForm
32 40
diff --git a/src/Operators.hs b/src/Operators.hs
index c5812ea..fa39e23 100644
--- a/src/Operators.hs
+++ b/src/Operators.hs
@@ -1,6 +1,4 @@
1module Operators ( 1module Operators (primitives) where
2 primitives
3 ) where
4 2
5import Control.Monad.Except 3import Control.Monad.Except
6import Error.Base (LispError (..), LispResult (..)) 4import Error.Base (LispError (..), LispResult (..))
diff --git a/src/Parser.hs b/src/Parser.hs
index 115203b..a7f5571 100644
--- a/src/Parser.hs
+++ b/src/Parser.hs
@@ -22,6 +22,7 @@ data Expr = List [Expr]
22 | FloatLiteral Double 22 | FloatLiteral Double
23 | BoolLiteral Bool 23 | BoolLiteral Bool
24 | Id String 24 | Id String
25 | NoReturn
25 deriving (Eq) 26 deriving (Eq)
26 27
27-- backslash double quote escapes a quote inside strings 28-- backslash double quote escapes a quote inside strings
@@ -127,3 +128,4 @@ instance Show Expr where
127 show (BoolLiteral True) = "#t" 128 show (BoolLiteral True) = "#t"
128 show (BoolLiteral False) = "#f" 129 show (BoolLiteral False) = "#f"
129 show (Id i) = i 130 show (Id i) = i
131 show NoReturn = ";;; environment extension"