-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathParser.hs
More file actions
316 lines (262 loc) · 7.82 KB
/
Parser.hs
File metadata and controls
316 lines (262 loc) · 7.82 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
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
--------------------------------------------------------------------
-- |
-- Module : Parser
-- Copyright : (c) Stephen Diehl 2013
-- License : MIT
-- Maintainer: [email protected]
-- Stability : experimental
-- Portability: non-portable
--
--------------------------------------------------------------------
module Parser where
import Text.Parsec
-- import Text.Parsec.String (parseFromFile)
import Control.Applicative ((<$>), liftA2)
import Control.Monad (foldM)
import qualified Text.Parsec.Expr as Ex
import qualified Text.Parsec.Token as Tok
import qualified Data.Vector.Unboxed as U
import Lexer
import Syntax
import DependentTypes.Core
int :: Parser FlExpr
int = PInt <$> fromInteger <$> integer
floating :: Parser FlExpr
floating = PFloat <$> float
binop = Ex.Infix (BinaryOp <$> op) Ex.AssocLeft
unop = Ex.Prefix (UnaryOp <$> op)
binary s assoc = Ex.Infix (reservedOp s >> return (BinaryOp s)) assoc
op :: Parser String
op = do
whitespace
o <- operator
whitespace
return o
binops = [[binary "=" Ex.AssocLeft]
,[binary "*" Ex.AssocLeft,
binary "/" Ex.AssocLeft]
,[binary "+" Ex.AssocLeft,
binary "-" Ex.AssocLeft]
,[binary "<" Ex.AssocLeft, binary ">" Ex.AssocLeft]]
-- helper parsers: lower case and upper case
lIdentifier = skipMany space >> lookAhead lower >> identifier
uIdentifier = skipMany space >> lookAhead upper >> identifier
expr :: Parser FlExpr
expr = Ex.buildExpressionParser (binops ++ [[binop]]) factor
-- expr = try vector <|> Ex.buildExpressionParser (binops ++ [[unop], [binop]]) factor
-- concrete type or type application
typeAp :: Parser FlExpr
typeAp = do
name <- uIdentifier
vars <- many $ try (Type <$> TCon <$> uIdentifier) <|> try ( Type <$> TVar <$> lIdentifier ) <|> (parens typeAp)
let tcon = TCon name
if (length vars == 0) then return $ Type tcon -- concrete type
else return $ Type $ foldl f tcon vars -- type application
where f acc t = TApp acc (extractType t)
-- concrete type only
concreteType :: Parser FlExpr
concreteType = uIdentifier >>= return . Type . TCon
-- helper function to extract Type and Var from FlExpr
extractType (Type t) = t
extractVar (Var v) = v
-- variable with type
variable :: Parser FlExpr
variable = do
name <- lIdentifier
typ <- try (reservedOp ":" *> parens typeAp) <|>
try (reservedOp ":" *> concreteType) <|>
try (reservedOp ":" *> typeVariable) <|>
pure (Type ToDerive)
return $ Var (Id name (extractType typ))
-- variables in records need to be handled differently
varInRecord :: Parser Var
varInRecord = do
name <- lIdentifier
typ <- try (reservedOp ":" *> parens typeAp) <|>
try (reservedOp ":" *> typeVariable) <|>
(reservedOp ":" *> typeAp)
return $ Id name (extractType typ)
-- type variable - Kind is always '*', needs to be adjusted at later stages
typeVariable :: Parser FlExpr
typeVariable = do
name <- lIdentifier
return $ Var (TyVar name KStar)
-- this, parametricType and dataDef parses haskell based data hello = Text a b | Nil type of data definitions
constructor :: Parser FlExpr
constructor = do
name <- uIdentifier
vars <- many (try ((Id "") <$> TCon <$> uIdentifier) <|> -- concrete type
try ((Id "") <$> TVar <$> lIdentifier) <|> -- type var
((Id "") <$> extractType <$> (parens typeAp)) -- complex type, like List a
<?> "regular constructor failed")
return $ Constructor name vars
recordConstructor :: Parser FlExpr
recordConstructor = do
name <- uIdentifier
whitespace >> char '{' >> whitespace
vars <- commaSep varInRecord
whitespace >> char '}' >> whitespace
return $ Constructor name vars
constructors = try recordConstructor <|> constructor
-- simple ADT
typeDef :: Parser FlExpr
typeDef = do
reserved "data"
name <- uIdentifier
vars <- many (extractVar <$> typeVariable)
reservedOp "="
fields <- sepBy1 constructors (char '|')
return $ TypeDef name vars fields
function :: Parser FlExpr
function = do
name <- lIdentifier
args <- many (extractVar <$> variable) -- (parens $ many identifier) <|> (parens $ commaSep identifier)
reservedOp "="
body <- expr
return $ Function name args body
extern :: Parser FlExpr
extern = do
reserved "extern"
name <- lIdentifier
args <- try (parens $ many identifier) <|> (parens $ commaSep identifier)
return $ Extern name args
symbolId :: Parser FlExpr
symbolId = identifier >>= return . SymId
{-
call :: Parser FlExpr
call = do
name <- identifier
args <- many $ try expr <|> parens expr
let acc = SymId name
if (length args == 0) then return $ acc
else let e = foldl f acc args in return e -- type application
where f acc arg = FlApp acc arg
-}
ifthen :: Parser FlExpr
ifthen = do
reserved "if"
cond <- expr
reserved "then"
tr <- expr
reserved "else"
fl <- expr
return $ FlIf cond tr fl
letins :: Parser FlExpr
letins = do
reserved "let"
defs <- commaSep function
reserved "in"
body <- expr
return $ FlLet defs body
unarydef :: Parser FlExpr
unarydef = do
reserved "def"
reserved "unary"
o <- op
args <- many (extractVar <$> variable)
reservedOp "="
body <- expr
return $ Function o args body
binarydef :: Parser FlExpr
binarydef = do
reserved "def"
reserved "binary"
o <- op
prec <- int <?> "integer: precedence value for the operator definition"
args <- many (extractVar <$> variable)
reservedOp "="
body <- expr
return $ Function o args body
argument :: Parser FlExpr
argument = try (parens expr)
<|> try vector
<|> try ifthen
<|> try floating
<|> try int
<|> symbolId
arguments :: Parser FlExpr
arguments = do
args <- many1 argument
return $ foldl FlApp (head args) (tail args)
factor :: Parser FlExpr
factor = try letins <|> arguments
-- <|> try variable
-- <|> try for
defn :: Parser FlExpr
defn = try extern
<|> try typeDef
<|> try function
<|> try unarydef
<|> try binarydef
<|> expr
-- <|> try record
-- contents :: Parser a -> Parser a
contents p = do
whitespace
r <- p
eof
return r
toplevel :: Parser [FlExpr]
toplevel = many $ do
def <- defn
reservedOp ";"
return def
-- parseExpr :: String -> Either ParseError Expr
parseExpr s = runParserT (contents expr) initialParserState "<stdin>" s
--parseToplevel :: String -> Either ParseError [Expr]
parseToplevel s = runParserT (contents defn) initialParserState "<stdin>" s
-- parse a given file
parseToplevelFile name = parseFromFile (contents toplevel) name initialParserState
-- parseFromFile :: Parser a -> String -> IO (Either ParseError a)
-- redefining parse from file to work with our state - just a quick and dirty fix
parseFromFile p fname st
= do input <- readFile fname
return (runP p st fname input)
-- adding new stuff
{-
-- simple (flat) record
record :: Parser Expr
record = do
reserved "data"
name <- uIdentifier
reservedOp "="
fields <- braces $ semiSep expr
return $ Record name [] fields
letins :: Parser Expr
letins = do
reserved "let"
defs <- semiSep $ do
var <- lIdentifier
reservedOp "="
val <- expr
return (var, val)
reserved "in"
body <- expr
return $ foldr (uncurry Let) body defs
for :: Parser Expr
for = do
reserved "for"
var <- identifier
reservedOp "="
start <- expr
reservedOp ","
cond <- expr
reservedOp ","
step <- expr
reserved "in"
body <- expr
return $ For var start cond step body
-}
-- numeric vector: <1,2,3.4>
vector :: Parser FlExpr
vector = do
-- we are checking something is between <>
-- then separating this input by commas
-- then for each expression - first trying to read it as a float then if it fails - as an int!
-- cool and beautiful!
args <- angles $ commaSep (try floating <|> int)
let l = map conv args where
conv (PInt i) = fromIntegral i
conv (PFloat f) = f
let v = U.fromList l
return $ VFloat v