Skip to content

Commit 46ca827

Browse files
committed
Refactoring
1 parent 44e08fd commit 46ca827

File tree

12 files changed

+166
-142
lines changed

12 files changed

+166
-142
lines changed

app/Main.hs

+8-6
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ import System.Environment
55
import System.Console.Haskeline
66
import Control.Monad.IO.Class
77

8-
import Interpreter
9-
import Parser
10-
import SExpr
8+
import Data.ParseTree
9+
import Data.Compiler
10+
import Data.SExpr
11+
import Interpreter.Eval
12+
import Runtime.Effect
1113
import Utils
1214

1315
-- Read input from keyboard
14-
readInputFragment :: String -> Int -> InputT IO (Maybe TokenTree)
16+
readInputFragment :: String -> Int -> InputT IO (Maybe ParseTree)
1517
readInputFragment str lines = do
1618
input <- getInputLine $ "[" ++ show lines ++ "]> "
1719
++ (concat $ replicate open "\t")
@@ -22,7 +24,7 @@ readInputFragment str lines = do
2224
Just str' -> case isBlank str' of
2325
True -> readInputFragment str lines
2426
False -> case numberOfOpenBrackets False (str ++ " " ++ str') >= 0 of
25-
True -> case reads (str ++ " " ++ str') :: [(TokenTree, String)] of
27+
True -> case reads (str ++ " " ++ str') :: [(ParseTree, String)] of
2628
[] -> readInputFragment (str ++ " " ++ str') (lines + 1)
2729
[(tree, str'')] -> case isBlank str'' of
2830
True -> liftIO $ return $ Just tree
@@ -31,7 +33,7 @@ readInputFragment str lines = do
3133
where
3234
open = numberOfOpenBrackets False str
3335

34-
readInput :: InputT IO (Maybe TokenTree)
36+
readInput :: InputT IO (Maybe ParseTree)
3537
readInput = readInputFragment "" 0
3638

3739
-- read-eval-print-loop for terminal

minilisp.cabal

+10-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ cabal-version: 1.12
44
--
55
-- see: https://github.com/sol/hpack
66
--
7-
-- hash: 8041b3b29d2e32ff95bde03f5a127e8844379ed7b96a3f64a33619a1d62394cf
7+
-- hash: a94600b5544fc2d8153c9072d05a8d5b75f1eec3ecbf19ac8191a561d1585b64
88

99
name: minilisp
1010
version: 0.1.0.0
@@ -26,9 +26,13 @@ source-repository head
2626

2727
library
2828
exposed-modules:
29-
Interpreter
30-
Parser
31-
SExpr
29+
Data.Compiler
30+
Data.ParseTree
31+
Data.SExpr
32+
Data.Token
33+
Interpreter.Eval
34+
Runtime.Effect
35+
Runtime.Error
3236
Utils
3337
other-modules:
3438
Paths_minilisp
@@ -62,8 +66,8 @@ test-suite minilisp-test
6266
type: exitcode-stdio-1.0
6367
main-is: Spec.hs
6468
other-modules:
65-
InterpreterTest
66-
ParserTest
69+
CompilerTest
70+
EvalTest
6771
Paths_minilisp
6872
hs-source-dirs:
6973
test

src/Parser.hs src/Data/Compiler.hs

+7-59
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,13 @@
1-
module Parser where
1+
module Data.Compiler where
22

33
import qualified Data.Map as Map
44

5-
import SExpr
5+
import Data.SExpr
6+
import Data.Token
7+
import Data.ParseTree
68
import Utils
79

8-
data Token = IntegerType Integer
9-
| DoubleType Double
10-
| BoolType Bool
11-
| StringType String
12-
| SymbType String
13-
deriving (Show, Eq)
14-
15-
data TokenTree = Empty
16-
| Leaf Token
17-
| Node TokenTree TokenTree deriving (Show, Eq)
18-
19-
instance Read Token where
20-
readsPrec _ str = case dropLeadingBlanks str of
21-
"" -> []
22-
'(':_ -> []
23-
')':_ -> []
24-
'.':_ -> []
25-
str' -> case reads str' :: [(String, String)] of
26-
[(x, s)] -> [(StringType x, s)]
27-
_ -> case reads str' :: [(Integer, String)] of
28-
[(x, s)] -> [(IntegerType x, s)]
29-
_ -> case reads str' :: [(Double, String)] of
30-
[(x, s)] -> [(DoubleType x, s)]
31-
_ -> case split str' of
32-
("#t", s) -> [(BoolType True, s)]
33-
("#f", s) -> [(BoolType False, s)]
34-
('\"':_, _) -> [] -- a symbol cannot begin with a double quote
35-
(str'', s) -> [(SymbType str'', s)]
36-
37-
instance Read TokenTree where
38-
readsPrec _ str = case dropLeadingBlanks str of
39-
"" -> []
40-
')':_ -> []
41-
'.':_ -> []
42-
'\'':str' -> case reads str' :: [(TokenTree, String)] of
43-
[(x, str'')] -> [(Node (Leaf (SymbType "\'")) (Node x Empty), str'')]
44-
_ -> [(Empty, '\'':str')]
45-
'(':str' -> case dropLeadingBlanks str' of
46-
')':str'' -> [(Empty, str'')]
47-
_ -> case reads str' :: [(TokenTree, String)] of
48-
[(x, str'')] -> case dropLeadingBlanks str'' of
49-
"" -> []
50-
')':str''' -> [(Node x Empty, str''')]
51-
'.':str''' -> case reads ('(':str''') :: [(TokenTree, String)] of
52-
[(Node y Empty, str'''')] -> [(Node x y, str'''')]
53-
_ -> []
54-
_ -> case reads ('(':str'') :: [(TokenTree, String)] of
55-
[(y, str''')] -> [(Node x y, str''')]
56-
_ -> []
57-
_ -> []
58-
_ -> case reads str :: [(Token, String)] of
59-
[(x, str')] -> [(Leaf x, str')]
60-
_ -> []
61-
62-
compile :: TokenTree -> Maybe SExpr
10+
compile :: ParseTree -> Maybe SExpr
6311
compile Empty = Just Nil
6412

6513
compile (Leaf (BoolType True)) = Just T
@@ -196,15 +144,15 @@ compile (Node x y) = do
196144
y' <- compile y
197145
return $ Pair x' y'
198146

199-
compileList :: TokenTree -> Maybe [SExpr]
147+
compileList :: ParseTree -> Maybe [SExpr]
200148
compileList Empty = Just []
201149
compileList (Node x y) = do
202150
x' <- compile x
203151
y' <- compileList y
204152
return (x':y')
205153
compileList _ = Nothing
206154

207-
compileCoupleList :: TokenTree -> Maybe [(SExpr, SExpr)]
155+
compileCoupleList :: ParseTree -> Maybe [(SExpr, SExpr)]
208156
compileCoupleList Empty = Just []
209157
compileCoupleList (Node (Node x (Node y Empty)) z) = do
210158
x' <- compile x

src/Data/ParseTree.hs

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
module Data.ParseTree where
2+
3+
import Data.Token
4+
import Utils
5+
6+
data ParseTree = Empty
7+
| Leaf Token
8+
| Node ParseTree ParseTree deriving (Show, Eq)
9+
10+
instance Read ParseTree where
11+
readsPrec _ str = case dropLeadingBlanks str of
12+
"" -> []
13+
')':_ -> []
14+
'.':_ -> []
15+
'\'':str' -> case reads str' :: [(ParseTree, String)] of
16+
[(x, str'')] -> [(Node (Leaf (SymbType "\'")) (Node x Empty), str'')]
17+
_ -> [(Empty, '\'':str')]
18+
'(':str' -> case dropLeadingBlanks str' of
19+
')':str'' -> [(Empty, str'')]
20+
_ -> case reads str' :: [(ParseTree, String)] of
21+
[(x, str'')] -> case dropLeadingBlanks str'' of
22+
"" -> []
23+
')':str''' -> [(Node x Empty, str''')]
24+
'.':str''' -> case reads ('(':str''') :: [(ParseTree, String)] of
25+
[(Node y Empty, str'''')] -> [(Node x y, str'''')]
26+
_ -> []
27+
_ -> case reads ('(':str'') :: [(ParseTree, String)] of
28+
[(y, str''')] -> [(Node x y, str''')]
29+
_ -> []
30+
_ -> []
31+
_ -> case reads str :: [(Token, String)] of
32+
[(x, str')] -> [(Leaf x, str')]
33+
_ -> []

src/SExpr.hs src/Data/SExpr.hs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module SExpr where
1+
module Data.SExpr where
22

33
data SExpr = Nil
44
| T
@@ -57,7 +57,6 @@ instance Show SExpr where
5757
isList (Pair x y) = isList y
5858
isList _ = False
5959
show (Lambda _ _) = "<function>"
60-
6160
show (CAR x) = "(car " ++ show x ++ ")"
6261
show (CDR x) = "(cdr " ++ show x ++ ")"
6362
show (CONS x y) = "(cons " ++ show x ++ " " ++ show y ++ ")"
@@ -73,11 +72,10 @@ instance Show SExpr where
7372
show (OR x) = "(or " ++ showSExprList x ++ ")"
7473
show (AND x) = "(and " ++ showSExprList x ++ ")"
7574
show (LIST x) = "(list " ++ showSExprList x ++ ")"
76-
show (COND x) = "(cond " ++ showSExprPairList ++ ")"
75+
show (COND x) = "(cond " ++ showSExprPairList x ++ ")"
7776
show (IF x y z) = "(if " ++ show x ++ " " ++ show y ++ " " ++ show z ++ ")"
7877
show (LABEL x y) = "(label " ++ show x ++ " " ++ show y ++ ")"
7978
show (LET x y z) = "(let " ++ show x ++ " " ++ show y ++ " " ++ show z ++ ")"
8079
show (DEFINE x y) = "(define " ++ show x ++ " " ++ show y ++ ")"
8180
show (MOD x y) = "(% " ++ show x ++ " " ++ show y ++ ")"
8281
show (NOT x) = "(not " ++ show x ++ ")"
83-
show _ = "<unevaluated>"

src/Data/Token.hs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
module Data.Token where
2+
3+
import Utils
4+
5+
data Token = IntegerType Integer
6+
| DoubleType Double
7+
| BoolType Bool
8+
| StringType String
9+
| SymbType String
10+
deriving (Show, Eq)
11+
12+
instance Read Token where
13+
readsPrec _ str = case dropLeadingBlanks str of
14+
"" -> []
15+
'(':_ -> []
16+
')':_ -> []
17+
'.':_ -> []
18+
str' -> case reads str' :: [(String, String)] of
19+
[(x, s)] -> [(StringType x, s)]
20+
_ -> case reads str' :: [(Integer, String)] of
21+
[(x, s)] -> [(IntegerType x, s)]
22+
_ -> case reads str' :: [(Double, String)] of
23+
[(x, s)] -> [(DoubleType x, s)]
24+
_ -> case split str' of
25+
("#t", s) -> [(BoolType True, s)]
26+
("#f", s) -> [(BoolType False, s)]
27+
('\"':_, _) -> [] -- a symbol cannot begin with a double quote
28+
(str'', s) -> [(SymbType str'', s)]

src/Interpreter.hs src/Interpreter/Eval.hs

+4-48
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,12 @@
1-
module Interpreter where
1+
module Interpreter.Eval where
22

33
import qualified Data.Map as Map
44

5-
import SExpr
5+
import Data.SExpr
6+
import Runtime.Error
7+
import Runtime.Effect
68
import Utils
79

8-
-- error data type
9-
data Error = RuntimeError String
10-
| UnexpectedArgNumError Integer
11-
| UnexpectedValueError SExpr
12-
| UnboundSymbolError String
13-
| DivisionByZeroError
14-
| UnexpectedExpressionError SExpr
15-
deriving Show
16-
17-
-- monad which wraps effectful computations (which may fail)
18-
data Effect a = Effect (IO (Either Error a))
19-
20-
instance Functor Effect where
21-
fmap f (Effect x) = Effect $ do
22-
x' <- x
23-
case x' of
24-
Left err -> do
25-
return $ Left err
26-
Right a -> return $ Right $ f a
27-
28-
instance Applicative Effect where
29-
pure a = Effect $ return $ Right a
30-
31-
(Effect f) <*> (Effect x) = Effect $ do
32-
x' <- x
33-
case x' of
34-
Left errx -> do
35-
return $ Left errx
36-
Right a -> do
37-
f' <- f
38-
case f' of
39-
Left errf -> do
40-
return $ Left errf
41-
Right g -> return $ Right $ g a
42-
43-
instance Monad Effect where
44-
(Effect x) >>= f = Effect $ do
45-
x' <- x
46-
case x' of
47-
Left err -> do
48-
return $ Left err
49-
Right a -> do
50-
let Effect y = f a
51-
y' <- y
52-
return y'
53-
5410
-- environment data type, where variables are stored
5511
type Env = Map.Map String SExpr
5612
type Ctx = [Env]

src/Runtime/Effect.hs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
module Runtime.Effect where
2+
3+
import Runtime.Error
4+
5+
-- monad which wraps effectful computations (which may fail)
6+
data Effect a = Effect (IO (Either Error a))
7+
8+
instance Functor Effect where
9+
fmap f (Effect x) = Effect $ do
10+
x' <- x
11+
case x' of
12+
Left err -> do
13+
return $ Left err
14+
Right a -> return $ Right $ f a
15+
16+
instance Applicative Effect where
17+
pure a = Effect $ return $ Right a
18+
19+
(Effect f) <*> (Effect x) = Effect $ do
20+
x' <- x
21+
case x' of
22+
Left errx -> do
23+
return $ Left errx
24+
Right a -> do
25+
f' <- f
26+
case f' of
27+
Left errf -> do
28+
return $ Left errf
29+
Right g -> return $ Right $ g a
30+
31+
instance Monad Effect where
32+
(Effect x) >>= f = Effect $ do
33+
x' <- x
34+
case x' of
35+
Left err -> do
36+
return $ Left err
37+
Right a -> do
38+
let Effect y = f a
39+
y' <- y
40+
return y'

src/Runtime/Error.hs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module Runtime.Error where
2+
3+
import Data.SExpr
4+
5+
-- error data type
6+
data Error = RuntimeError String
7+
| UnexpectedArgNumError Integer
8+
| UnexpectedValueError SExpr
9+
| UnboundSymbolError String
10+
| DivisionByZeroError
11+
| UnexpectedExpressionError SExpr
12+
deriving Show

0 commit comments

Comments
 (0)