-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathParser.hs
154 lines (123 loc) · 3.69 KB
/
Parser.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
153
154
module Parser (parse_expr, parse_code) where
import Control.Monad
import Control.Applicative
import Expr
import Control.Applicative (Alternative(..))
import Data.Char (isAlpha, isSpace, isAlphaNum)
-- Parser data type
newtype Parser a = Parser {
parse :: String -> Maybe(a, String)
}
--- type declaration ---
instance Functor Parser where
fmap f (Parser p) = Parser $ \input -> do
(result, rest) <- p input
Just (f result, rest)
instance Applicative Parser where
pure x = Parser $ \input -> Just (x, input)
(Parser p1) <*> (Parser p2) = Parser $ \input -> do
(f, rest1) <- p1 input
(x, rest2) <- p2 rest1
Just (f x, rest2)
instance Alternative Parser where
empty = Parser $ const Nothing
(Parser p1) <|> (Parser p2) = Parser $ \input -> p1 input <|> p2 input
instance Monad Parser where
(Parser p) >>= f = Parser $ \input -> do
(result, rest) <- p input
parse (f result) rest
satisfy :: (Char -> Bool) -> Parser Char
satisfy predicate = Parser $ \input ->
case input of
c:rest | predicate c -> Just (c, rest)
_ -> Nothing
char :: Char -> Parser Char
char c = satisfy (== c)
string :: String -> Parser String
string "" = pure ""
string (c:cs) = (:) <$> char c <*> string cs
spaces :: Parser ()
spaces = () <$ many (satisfy isSpace)
variable :: Parser Expr
variable = do
isMacro <- optional1 (char '$')
case isMacro of
Just _ -> Macro <$> name
Nothing -> Variable <$> name
where
name :: Parser String
name = some (satisfy isAlpha)
function :: Parser Expr
function = do
char '\\'
spaces
vars <- variable `sepBy` (char ',')
spaces
char '.'
spaces
body <- atom <|> parenthesizedExpr
case vars of
[] -> pure body
_ -> foldr (\v acc -> Function (getVarName v) <$> acc) (pure body) vars
parenthesizedExpr :: Parser Expr
parenthesizedExpr = do
char '('
spaces
expr <- expr
spaces
char ')'
pure expr
sepBy :: Parser a -> Parser sep -> Parser [a]
sepBy p sep = (:) <$> p <*> many (sep *> p) <|> pure []
optional1 :: Parser a -> Parser (Maybe a)
optional1 p = (Just <$> p) <|> pure Nothing
application :: Parser Expr
application = do
expr1 <- atom
applicationRest expr1
where
applicationRest :: Expr -> Parser Expr
applicationRest exprSoFar = do
spaces
mbExpr <- optional1 atom
case mbExpr of
Just expr -> applicationRest (Application exprSoFar expr)
Nothing -> return exprSoFar
atom :: Parser Expr
atom = variable <|> function <|> (char '(' *> spaces *> expr <* spaces <* char ')')
macro1 :: Parser Expr
macro1 = do
_ <- char '$'
name <- some (satisfy isAlpha)
pure (Macro name)
expr :: Parser Expr
expr = application <|> atom
getVarName :: Expr -> String
getVarName (Variable name) = name
getVarName _ = ""
parse_expr :: String -> Expr
parse_expr input =
case parse expr input of
Just (result, "") -> result
_ -> Variable "123"
-- TODO 4.2. parse code
parse_code :: String -> Code
parse_code input =
case parse codeParser input of
Just (result, "") -> result
_ -> case parse exprParser input of
Just (expr, "") -> Evaluate expr
_ -> Evaluate (Variable "123")
codeParser :: Parser Code
codeParser = assignParser <|> evaluateParser
assignParser :: Parser Code
assignParser = do
varName <- spaces *> identifier <* spaces <* char '=' <* spaces
lambdaExpr <- exprParser
return (Assign varName lambdaExpr)
evaluateParser :: Parser Code
evaluateParser = Evaluate <$> exprParser
identifier :: Parser String
identifier = some (satisfy isAlphaNum)
exprParser :: Parser Expr
exprParser = application <|> atom