-
Notifications
You must be signed in to change notification settings - Fork 0
/
Parse.hs
152 lines (129 loc) · 4.72 KB
/
Parse.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
152
module Parse where
import Text.ParserCombinators.Parsec
import Expr
parseExpr :: Parser Expr
parseExpr = try parseFloat <|>
try parseInteger <|>
try parseBoolean <|>
try parseChar <|>
try parseLambda <|>
parseQuote <|>
parseString <|>
parseSymbol <|>
try parseConsList <|>
try parseRangeList <|>
try parseRangeList2 <|>
try parseInfRangeList <|>
try parseInfRangeList2 <|>
parseList
parseFloat :: Parser Expr
parseFloat = do sign <- option "" (string "+" <|> string "-")
integerPart <- many1 digit
char '.'
realPart <- many1 digit
return $ LispFloat $ read $ (if sign == "-" then sign else "") ++ integerPart ++ "." ++ realPart
parseInteger :: Parser Expr
parseInteger = do sign <- option "" (string "+" <|> string "-")
i <- many1 digit
return $ LispInteger (read ((if sign == "-" then sign else "") ++ i))
parseBoolean :: Parser Expr
parseBoolean = do p <- string "true" <|> string "false"
return $ LispBoolean (p == "true")
parseChar :: Parser Expr
parseChar = do _ <- char '\''
ch <- noneOf "'"
_ <- char '\''
return $ LispChar ch
parseQuote :: Parser Expr
parseQuote = do _ <- char '\''
expr <- parseExpr
return $ LispList [LispSymbol "quote", expr]
escape :: Parser String
escape = do
d <- char '\\'
c <- oneOf "\\\"0nrvtbf" -- all the characters which can be escaped
return [d, c]
nonEscape :: Parser Char
nonEscape = noneOf "\\\"\0\n\r\v\t\b\f"
character :: Parser String
character = fmap return nonEscape <|> escape
getEscape :: Char -> Char
getEscape ch = case ch of
'\"' -> '\"'
'0' -> '\0'
'n' -> '\n'
'r' -> '\r'
'v' -> '\v'
't' -> '\t'
'b' -> '\b'
'f' -> '\f'
transEscape :: String -> Char
transEscape str = if head str == '\\' then getEscape (str !! 1) else head str
parseString :: Parser Expr
parseString = do _ <- char '"'
str <- many character
_ <- char '"'
return $ LispDataList $ map (LispChar . transEscape) str
parseSymbol :: Parser Expr
parseSymbol = do first <- firstChar
trailing <- many (firstChar <|> digit)
return $ LispSymbol (first:trailing)
where firstChar = oneOf "+-*/%=?><" <|> letter
parseConsList :: Parser Expr
parseConsList = do _ <- char '['
lst <- sepBy parseExpr spaces
_ <- char ']'
return $ LispDataList lst
parseRangeList :: Parser Expr
parseRangeList = do char '['
begin <- parseExpr
spaces
char '~'
spaces
end <- parseExpr
_ <- char ']'
return $ LispRangeList begin end
parseRangeList2 :: Parser Expr
parseRangeList2 = do _ <- char '['
begin <- parseExpr
_ <- spaces
begin2 <- parseExpr
_ <- spaces
_ <- char '~'
_ <- spaces
end <- parseExpr
_ <- char ']'
return $ LispRangeList2 begin begin2 end
parseInfRangeList :: Parser Expr
parseInfRangeList = do char '['
begin <- parseExpr
spaces
char '~'
spaces
_ <- char ']'
return $ LispInfRangeList begin
parseInfRangeList2 :: Parser Expr
parseInfRangeList2 = do _ <- char '['
begin <- parseExpr
_ <- spaces
begin2 <- parseExpr
_ <- spaces
_ <- char '~'
_ <- spaces
_ <- char ']'
return $ LispInfRangeList2 begin begin2
parseLambda :: Parser Expr
parseLambda = do _ <- oneOf "\\λ"
args <- sepEndBy parseSymbol spaces
_ <- string "."
_ <- spaces
body <- parseExpr
return $ LispList [LispSymbol "lambda", LispList args, body]
parseList :: Parser Expr
parseList = do _ <- char '('
lst <- sepEndBy parseExpr spaces
_ <- char ')'
return $ LispList lst
parseExprs :: Parser Expr
parseExprs = do exprs <- sepEndBy parseExpr spaces
return $ LispDo exprs