-
Notifications
You must be signed in to change notification settings - Fork 2
/
Parser.hs
119 lines (100 loc) · 2.79 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
-- Some function signatures are too cryptic, so we're leaving them out.
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
module Parser where
import Prelude hiding (GT, LT)
import Text.Parsec
import Text.Parsec.String (Parser)
import qualified Text.Parsec.Expr as Exp
import Lexer
import Syntax
import Error
basicType :: Parser Ty
basicType = do
tyName <- identifier
case tyName of
"Int" -> return IntTy
"Bool" -> return BoolTy
_ -> errorUnknownType tyName
rcdType :: Parser Ty
rcdType = do
reserved "{"
fields <- sepBy rcdFieldType (spaces *> char ',' <* spaces)
reserved "}"
return $ RcdTy fields
rcdFieldType = do
lbl <- identifier
reserved ":"
ty <- typeParsers
return (lbl, ty)
basicTypes = basicType <|> rcdType
fnType :: Parser Ty
fnType = do
ty1 <- try basicTypes <|> parens fnType
reserved "->"
ty2 <- try basicTypes <|> parens fnType
return $ ArrowTy ty1 ty2
typeParsers :: Parser Ty
typeParsers = basicTypes <|> fnType
exprType :: Parser Ty
exprType = do
reserved "::"
typeParsers
intExpr :: Parser Expr
intExpr = do
n <- integer
return $ I (fromInteger n) IntTy -- n is an Integer, we want Int
varExpr :: Parser Expr
varExpr = do
var <- identifier
case var of
"true" -> return $ B True BoolTy
"false" -> return $ B False BoolTy
v -> return $ Var v
-- Anonymous function
-- e.g. fn x => x + 1
fnExpr :: Parser Expr
fnExpr = do
reserved "fn"
var <- identifier
reserved "::"
ty <- parens fnType
reserved "=>"
body <- expr
return $ Fn var body ty
-- Records
-- Nested records are permitted
-- e.g. { a = 2, foo = true, c = 4 + 2, d = { bar = false } }
rcdExpr :: Parser Expr
rcdExpr = do
reserved "{"
fields <- sepBy rcdField (spaces *> char ',' <* spaces)
reserved "}"
ty <- exprType
return $ Rcd fields ty
rcdField = do
lbl <- identifier
reserved "="
value <- expr
return (lbl, value)
expr :: Parser Expr
expr = Exp.buildExpressionParser opTable exprParsers
-- The table of operations on expressions.
--
-- Parsec uses this table to take care of associativity and precedence automatically.
-- The table is ordered by descending precedence, where operators in the same row having the same precedence.
opTable = [[Exp.Infix spacef Exp.AssocLeft],
[projectionOp "." Exp.AssocLeft]]
where
projectionOp s = Exp.Infix $ reservedOp s >> return RcdProj
-- Treat spaces as a binary operator for function application
-- http://stackoverflow.com/questions/22904287/parsing-functional-application-with-parsec
spacef = whiteSpace
*> notFollowedBy (choice . map reservedOp $ opNames)
>> return FApp
exprParsers = varExpr
<|> fnExpr
<|> rcdExpr
<|> intExpr
<|> parens expr
parseExpr :: String -> Either ParseError Expr
parseExpr = parse expr ""