-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathParser.lhs
More file actions
125 lines (99 loc) · 3.1 KB
/
Parser.lhs
File metadata and controls
125 lines (99 loc) · 3.1 KB
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
\begin{code}
module Parser (parseStr, Expr(..), Symbol) where
import Text.Parsec ((<|>), (<?>), try, eof, many1)
import Text.Parsec.Combinator (optional, optionMaybe, sepBy, sepEndBy1)
import Text.Parsec.Prim (parse)
import Text.Parsec.Char (newline)
import Text.Parsec.String (Parser)
import Text.Parsec.Expr (buildExpressionParser, Operator(..), Assoc(..))
import Lexer
type Symbol = String
data Expr = BoolLit Bool
| NumLit Double
| StrLit String
| Ident Symbol
| BinOp String Expr Expr
| UniOp String Expr
| Lambda [Symbol] Expr
| Application Expr [Expr]
| Multi [Expr]
| If Expr Expr (Maybe Expr)
deriving (Show, Eq)
expr :: Parser Expr
primary :: Parser Expr
boolean :: Parser Expr
number :: Parser Expr
lambda :: Parser Expr
application :: Parser Expr
multi :: Parser Expr
if' :: Parser Expr
asStrLit = return . StrLit
asIdent = return . Ident
asMulti = return . Multi
program = do
whiteSpace
x <- sepEndBy1 expr semi >>= asMulti
eof
return x
primary = try application
<|> parens expr
<|> multi
<|> if'
<|> (stringLiteral >>= asStrLit)
<|> (identifier >>= asIdent)
<|> boolean
<|> number
<|> lambda
<?> "simple expression"
expr = buildExpressionParser table primary
<?> "expression"
table = [[prefix "-"],
[postfix "++", postfix "--"],
[binary "*" AssocLeft, binary "/" AssocLeft],
[binary "+" AssocLeft, binary "-" AssocLeft],
[binary "==" AssocLeft, binary "!=" AssocLeft,
binary "<" AssocLeft, binary ">" AssocLeft,
binary "<=" AssocLeft, binary ">=" AssocLeft,
prefix "!"],
[binary "=" AssocRight],
[binary "&&" AssocLeft, binary "||" AssocLeft]]
binary name assoc = Infix (exprRule name BinOp) assoc
prefix name = Prefix (exprRule name UniOp)
postfix name = Postfix (exprRule name UniOp)
exprRule name f = reservedOp name >> return (f name)
<?> "operator"
boolean = (reserved "true" >> return (BoolLit True))
<|> (reserved "false" >> return (BoolLit False))
number = do
num <- naturalOrFloat
return $ case num of
Left x -> NumLit (fromIntegral x)
Right x -> NumLit x
lambda = do
symbol "\\"
args <- many1 identifier
symbol "->"
e <- expr
return (Lambda args e)
application = do
func <- parens expr <|> (identifier >>= asIdent)
let argList = sepBy expr (symbol ",")
args <- parens argList
return (Application func args)
multi = braces (sepEndBy1 expr semi >>= asMulti)
if' = do
reserved "if"
test <- expr
then' <- multi
else' <- optionMaybe (reserved "else" >> multi)
return (If test then' else')
parseStr :: String -> IO Expr
parseStr = parseStr' program
parseStr' :: Parser Expr -> String -> IO Expr
parseStr' p input
= case parse p "" input of
Left err -> do putStrLn "parse error"
print err
return (NumLit 0)
Right ast -> return ast
\end{code}