-
Notifications
You must be signed in to change notification settings - Fork 0
/
Sexpr.hs
152 lines (121 loc) · 4.13 KB
/
Sexpr.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
-- scheme 48
-- Parser and def for LispVar
module Sexpr (parseExpr, parseLine, LispVal(..)) where
{-
Problem with current impl of parsing:
1. can only read line by line
2. the rest of line is ignored and discarded once a valid sexpr is found
3. handle whiltspaces and line break outside of sexpr
-}
import Text.Parsec
import Text.Parsec.String
import qualified Text.Parsec.Token as T
import Text.Parsec.Language
import Data.List
import Control.Monad
parseLine = parse (spaces >> parseExpr) "scheme"
-- readExprEither :: String -> Either (??) LispVal
readExprEither = parseLine
readExprError :: String -> LispVal
readExprError input = case parseLine input of
Left err -> error $ "Parse Error " ++ show err
Right val -> val
readExprShow :: String -> String
readExprShow input = case parseLine input of
Left err -> "Parse Error : " ++ show err
Right val -> show val
----------------------------------
data LispVal = Atom String
| List [LispVal]
| DottedList [LispVal] LispVal
-- dotted list or improper list
-- is a list that doesn't end with []
-- but something else
| Number Integer
| String String
| Bool Bool
deriving (Eq)
instance Show LispVal where
show val = case val of
Atom str -> str
List xs -> "(" ++ unwordsList xs ++ ")"
DottedList xs x ->"(" ++ unwordsList xs ++ " . " ++ show x ++ ")"
String str -> show str
Bool bool -> if bool then "#t" else "#f"
Number num -> show num
unwordsList :: [LispVal] -> String
unwordsList = unwords . map show
---------------------------------------------
symbol :: Parser Char
symbol = oneOf "!$%&|*+-/#:<=>?@^_~"
quoteTypes = [("'", "quote"), ("`", "backquote")]
mkQuotedParser :: [(String, String)] -> Parser LispVal
mkQuotedParser xs = foldr1 (<|>) (map (\(x, y) -> parseQuoted x y) xs)
parseExpr :: Parser LispVal
parseExpr = try parseAtom
<|> parseString
<|> parseNumber
<|> mkQuotedParser quoteTypes
<|> do char '('
x <- parseList'
char ')'
return x
parseNumber :: Parser LispVal
-- parseNumber = liftM (Number . read) $ many1 digit
parseNumber = liftM Number pInteger
parseAtom :: Parser LispVal
parseAtom = do
first <- letter <|> symbol
rest <- many (letter <|> digit <|> symbol )
let atom = first : rest
return $ case atom of
"#t" -> Bool True
"#f" -> Bool False
_ -> Atom atom
wrapped :: Char -> Char -> Parser a -> Parser a
wrapped pre post m = do char pre
a <- m
char post
return a
parseAnotherList = wrapped '[' ']' $ do
lst <- sepBy parseExpr spaces
return $ List lst
lexer = T.makeTokenParser emptyDef
pStr :: Parser String
pStr = T.stringLiteral lexer
pInteger :: Parser Integer
pInteger = T.integer lexer
{-
- pStr :: Parser String | m a, where m = Parser, a = String
- pLispString :: Parser LispVal | m b, where m = Parser, b = LispVal
- String :: String -> LispVal | a -> b, where a = ..., b = ...
- return :: b -> m b
- (>>=) :: m a -> (a -> m b) -> m b
- (.) :: (b -> c) -> (a -> b) -> a -> c
-
pLispString :: Parser LispVal
pLispString = do str <- pStr
return $ String str
-}
parseString :: Parser LispVal
parseString = liftM String pStr
parseList :: Parser LispVal
parseList = liftM List $ sepBy parseExpr spaces
parseDottedList :: Parser LispVal
parseDottedList = do
head <- endBy parseExpr spaces
tail <- char '.' >> spaces >> parseExpr
return $ DottedList head tail
parseList' :: Parser LispVal
parseList' = do
head <- endBy parseExpr spaces
tail <- (liftM Just) (char '.' >> spaces >> parseExpr) <|> return Nothing
return $ case tail of
Nothing -> List head
Just xs -> DottedList head xs
-- modify to support quasiquoataion
parseQuoted :: String -> String -> Parser LispVal
parseQuoted leadingSymbol quoteType = do
string leadingSymbol
x <- parseExpr
return $ List [Atom quoteType, x]