-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathParser.hs
464 lines (398 loc) · 10.8 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
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
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
module Parser(
Program (PROGRAM),
VarDeclaration (VAR_DECL),
VarDefinition (VAR_DEFN),
Declaration (..),
Constraint (..),
Distance (..),
Identifier,
parseProgram) where
import Text.ParserCombinators.Parsec
import System.Environment
import Data.Map as Map
import Data.List as List
import Data.Char
-- The first set of constraints are involved in the construction
-- The second set consist of the assertions about the construction.
data Program = PROGRAM [VarDeclaration] [VarDefinition] [Declaration] [Constraint] [Constraint]
deriving Show
-- Declare a free variable
newtype VarDeclaration = VAR_DECL Identifier
deriving Show
-- Point X = (a/b, c/d)
data VarDefinition = VAR_DEFN Identifier Integer Integer Integer Integer
deriving Show
-- first arg is the name of the variable
data Declaration = DEC_FOLD1 Identifier Identifier Identifier
| DEC_FOLD2 Identifier Identifier Identifier
| DEC_FOLD3 Identifier Identifier Identifier
| DEC_FOLD4 Identifier Identifier Identifier
| DEC_FOLD5 Int Identifier Identifier Identifier Identifier
| DEC_FOLD6 Int Identifier Identifier Identifier Identifier Identifier
| DEC_FOLD7 Identifier Identifier Identifier Identifier
| DEC_INTERSECT Identifier Identifier Identifier
deriving Show
--Define a constraint
data Constraint = CN_AND Constraint Constraint
| CN_OR Constraint Constraint
| CN_NEG Constraint
| CN_PARALLEL Identifier Identifier
| CN_PERPENDICULAR Identifier Identifier
| CN_COLINEAR Identifier Identifier
| CN_ANG_EQ Angle Angle
| CN_ANG_GT Angle Angle
| CN_ANG_LT Angle Angle
| CN_DIST_EQ Distance Distance
| CN_DIST_LT Distance Distance
| CN_DIST_GT Distance Distance
deriving Show
data Distance = DIST Identifier Identifier
| DIST_BINOP Distance Char Distance
| DIST_CONST Integer
deriving Show
data Angle = ANGLE Identifier Identifier Identifier
deriving Show
type Identifier = String
parseProgram :: String -> Program
parseProgram str = case parse program "Invalid Parse" str of
Left x -> error (show x)
Right x -> x
program :: Parser Program
program = do
many ignore
vardeclarations <- many vardeclaration
vardefinitions <- many vardefinition
declarations <- many declaration
constructions <- many construct
assertions <- many assert
eof
return $ PROGRAM vardeclarations vardefinitions declarations constructions assertions
vardeclaration :: Parser VarDeclaration
vardeclaration = do
string "VAR"
whitespace
name <- identifier
endCommand
return $ VAR_DECL name
vardefinition :: Parser VarDefinition
vardefinition = do
string "DEFINE"
whitespace
name <- identifier
whitespace
string "="
whitespace
a <- many1 digit
whitespace
b <- many1 digit
whitespace
c <- many1 digit
whitespace
d <- many1 digit
endCommand
return $ VAR_DEFN name (read a) (read b) (read c) (read d)
declaration :: Parser Declaration
declaration = try fold1dec
<|> try fold2dec
<|> try fold3dec
<|> try fold4dec
<|> try fold5decSol1
<|> try fold5decSol2
<|> try fold6dec
<|> try fold7dec
<|> try intersectdec
fold1dec :: Parser Declaration
fold1dec = decmaker "fold1" DEC_FOLD1
fold2dec :: Parser Declaration
fold2dec = decmaker "fold2" DEC_FOLD2
fold3dec :: Parser Declaration
fold3dec = decmaker "fold3" DEC_FOLD3
fold4dec :: Parser Declaration
fold4dec = decmaker "fold4" DEC_FOLD4
-- Move first arg point over fold crossing arg2 onto line arg3
fold5decSol1 :: Parser Declaration
fold5decSol1 = ternarydecmaker "fold5_1" $ DEC_FOLD5 1
fold5decSol2 :: Parser Declaration
fold5decSol2 = ternarydecmaker "fold5_2" $ DEC_FOLD5 2
fold6dec :: Parser Declaration
fold6dec = try fold6decsol1
<|> try fold6decsol2
<|> try fold6decsol3
fold6decsol1 :: Parser Declaration
fold6decsol1 = quaternarydecmaker "fold6_1" $ DEC_FOLD6 1
fold6decsol2 :: Parser Declaration
fold6decsol2 = quaternarydecmaker "fold6_2" $ DEC_FOLD6 2
fold6decsol3 :: Parser Declaration
fold6decsol3 = quaternarydecmaker "fold6_3" $ DEC_FOLD6 3
fold7dec :: Parser Declaration
fold7dec = ternarydecmaker "fold7" DEC_FOLD7
ternarydecmaker :: String
-> (Identifier
-> Identifier
-> Identifier
-> Identifier
-> Declaration)
-> Parser Declaration
ternarydecmaker str cons = do
varname <- identifier
whitespace
char '='
whitespace
string str
whitespace
pointMove <- identifier
whitespace
pointCenter <- identifier
whitespace
line <- identifier
endCommand
return $ cons varname pointMove pointCenter line
quaternarydecmaker :: String
-> (Identifier
-> Identifier
-> Identifier
-> Identifier
-> Identifier
-> Declaration)
-> Parser Declaration
quaternarydecmaker str cons = do
varname <- identifier
whitespace
char '='
whitespace
string str
whitespace
p1 <- identifier
whitespace
l1 <- identifier
whitespace
p2 <- identifier
whitespace
l2 <- identifier
endCommand
return $ cons varname p1 l1 p2 l2
intersectdec :: Parser Declaration
intersectdec = decmaker "intersect" DEC_INTERSECT
construct :: Parser Constraint
construct = do
string "CONSTRUCT"
whitespace
cn <- constraintInt
endl
many ignore
return cn
assert :: Parser Constraint
assert= do
string "ASSERT"
whitespace
cn <- constraintInt
endl
many ignore
return cn
constraintInt :: Parser Constraint
constraintInt = try constraintAnd
<|> try constraintOr
<|> try constraintNeg
<|> try constraintParallel
<|> try constraintPerpendicular
<|> try constraintColinear
<|> try constraintAngle
<|> constraintDist
constraintAnd :: Parser Constraint
constraintAnd = constraintGen "AND" CN_AND
constraintOr :: Parser Constraint
constraintOr = constraintGen "OR" CN_OR
constraintGen :: String
-> (Constraint -> Constraint -> Constraint)
-> Parser Constraint
constraintGen str constructor = do
string str
whitespace
char '('
whitespace
cn1 <- constraintInt
char ')'
whitespace
char '('
whitespace
cn2 <- constraintInt
char ')'
whitespace
return $ constructor cn1 cn2
constraintNeg :: Parser Constraint
constraintNeg = do
string "NOT"
whitespace
char '('
whitespace
cn <- constraintInt
char ')'
whitespace
return $ CN_NEG cn
constraintParallel :: Parser Constraint
constraintParallel = do
string "isParallel"
whitespace
var1 <- identifier
whitespace
var2 <- identifier
whitespace
return $ CN_PARALLEL var1 var2
constraintPerpendicular :: Parser Constraint
constraintPerpendicular = do
string "isPerpendicular"
whitespace
var1 <- identifier
whitespace
var2 <- identifier
whitespace
return $ CN_PERPENDICULAR var1 var2
constraintColinear :: Parser Constraint
constraintColinear = do
string "isColinear"
whitespace
point <- identifier
whitespace
line <- identifier
whitespace
return $ CN_COLINEAR point line
constraintAngle :: Parser Constraint
constraintAngle = try angleEq
<|> try angleLt
<|> try angleGt
constraintDist :: Parser Constraint
constraintDist = try distEq
<|> try distLt
<|> try distGt
decmaker :: String
-> (Identifier
-> Identifier
-> Identifier
-> Declaration)
-> Parser Declaration
decmaker str cons = do
varname <- identifier
whitespace
char '='
whitespace
string str
whitespace
arg1 <- identifier
whitespace
arg2 <- identifier
endCommand
return $ cons varname arg1 arg2
dist :: Parser Distance
dist = try distBinop
<|> try distGen
<|> distConst
distGen :: Parser Distance
distGen = do
string "d("
whitespace
p1 <- identifier
whitespace
p2 <- identifier
whitespace
string ")"
whitespace
return $ DIST p1 p2
distBinop :: Parser Distance
distBinop = do
char '('
whitespace
d1 <- dist
whitespace
op <- binop
whitespace
d2 <- dist
whitespace
char ')'
whitespace
return $ DIST_BINOP d1 op d2
distConst :: Parser Distance
distConst = do
top <- many1 digit
--TODO support floats
whitespace
return $ DIST_CONST (read top)
distEq :: Parser Constraint
distEq = distDecGenerator "==" CN_DIST_EQ
distLt :: Parser Constraint
distLt = distDecGenerator "<" CN_DIST_LT
distGt :: Parser Constraint
distGt = distDecGenerator ">" CN_DIST_GT
angleEq :: Parser Constraint
angleEq = angleDecGenerator "==" CN_ANG_EQ
angleLt :: Parser Constraint
angleLt = angleDecGenerator "<" CN_ANG_LT
angleGt :: Parser Constraint
angleGt = angleDecGenerator ">" CN_ANG_GT
distDecGenerator :: String -> (Distance -> Distance -> Constraint) -> Parser Constraint
distDecGenerator str cons = do
d1 <- dist
string str
whitespace
d2 <- dist
return $ cons d1 d2
angleDecGenerator :: String -> (Angle -> Angle -> Constraint) -> Parser Constraint
angleDecGenerator str cons = do
ang1 <- angle
string str
whitespace
ang2 <- angle
return $ cons ang1 ang2
angle :: Parser Angle
angle = do
string "/_"
whitespace
arg1 <- identifier
whitespace
arg2 <- identifier
whitespace
arg3 <- identifier
whitespace
return $ ANGLE arg1 arg2 arg3
identifierChar :: Char -> Bool
identifierChar c = (isAlphaNum c) || (c == '_')
identifier :: Parser Identifier
identifier = many $ satisfy identifierChar -- alphaNum
endCommand :: Parser ()
endCommand = do
whitespace
endl
many ignore
return ()
ignore :: Parser ()
ignore = comment <|> whiteline
whiteline :: Parser ()
whiteline = do
whitespace
endl
comment :: Parser ()
comment = do
char ';'
manyTill anyChar endl
return ()
endln :: Parser ()
endln = do
char '\n'
return ()
endlrn :: Parser ()
endlrn = do
char '\r'
char '\n'
return ()
endl :: Parser ()
endl = try endln
<|> try endlrn
whitespace :: Parser ()
whitespace = do
many $ satisfy isWhiteSpace
return ()
binop :: Parser Char
binop = try (char '+') <|> try (char '*') <|> try (char '-') <|> char '/'
isWhiteSpace :: Char -> Bool
isWhiteSpace ' ' = True
isWhiteSpace '\t' = True
isWhiteSpace _ = False