-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathSpec.hs
554 lines (507 loc) · 17.2 KB
/
Spec.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
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
{-# LANGUAGE CPP #-}
{-# LANGUAGE ParallelListComp #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
#ifdef USE_AESON
import qualified Data.ByteString.Lazy as BS
import Error.Diagnose(diagnosticToJson)
#endif
import Data.HashMap.Lazy (HashMap)
import qualified Data.HashMap.Lazy as HashMap
import Error.Diagnose
( Marker (..),
Note (..),
Position (..),
Report(..),
addFile,
addReport,
defaultStyle,
printDiagnostic,
printDiagnostic',
stdout,
WithUnicode (..),
TabSize (..),
)
import System.IO (hPutStrLn)
import Prettyprinter (Doc, annotate, pretty, hsep, indent, vsep, nest, (<+>), align, list)
import Prettyprinter.Util (reflow)
import Prettyprinter.Render.Terminal (AnsiStyle, Color (..), color, bold, italicized, underlined)
import Data.Traversable (mapAccumL)
import Data.Functor.Compose (Compose(..))
main :: IO ()
main = do
let files :: HashMap FilePath String =
HashMap.fromList
[ ("test.zc", "let id<a>(x : a) : a := x + 1\nrec fix(f) := f(fix(f))\nlet const<a, b>(x : a, y : b) : a := x"),
("somefile.zc", "let id<a>(x : a) : a := x\n + 1"),
("err.nst", "\n\n\n\n = jmp g\n\n g: forall(s: Ts, e: Tc).{ %r0: *s64 | s -> e }"),
("unsized.nst", "main: forall(a: Ta, s: Ts, e: Tc).{ %r5: forall().{| s -> e } | s -> %r5 }\n = salloc a\n ; sfree\n"),
("unicode.txt", "±⅀\t★♲♥🎉汉⑳⓴ჳᏁℳ爪"),
("gaps.txt", "abc\ndef\nghi\njkl\nmno\npqr"),
("repro3.file", "\n\n ayo yoa\n a b\n c d e f g\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nlayer qwertyy using yoooo: \"a\" \"b\" \"c\"\n")
]
let reports =
[ errorNoMarkersNoHints,
errorSingleMarkerNoHints,
warningSingleMarkerNoHints,
errorTwoMarkersSameLineNoOverlapNoHints,
errorSingleMarkerOutOfBoundsNoHints,
errorTwoMarkersSameLineOverlapNoHints,
errorTwoMarkersSameLinePartialOverlapNoHints,
errorTwoMarkersTwoLinesNoHints,
realWorldExample,
errorTwoMarkersSamePositionNoHints,
errorThreeMarkersWithOverlapNoHints,
errorWithMultilineErrorNoMarkerNoHints,
errorSingleMultilineMarkerMessageNoHints,
errorTwoMarkersSameOriginOverlapNoHints,
errorNoMarkersSingleHint,
errorNoMarkersSingleMultilineHint,
errorNoMarkersTwoHints,
errorSingleMultilineMarkerNoHints,
errorTwoMarkersWithMultilineNoHints,
errorTwoMultilineMarkersNoHints,
errorSingleMultilineMarkerMultilineMessageNoHints,
errorTwoMultilineMarkersFirstMultilineMessageNoHints,
errorThreeMultilineMarkersTwoMultilineMessageNoHints,
errorOrderSensitive,
errorMultilineAfterSingleLine,
errorOnEmptyLine,
errorMultipleFiles,
errorWithCode,
errorWithStrangeUnicodeInput,
errorWithMultilineMarkerOn3Lines,
errorMultilineMarkerNotAtEnd,
errorWithLineGap,
repro3,
errorWithMultilineMarkerMessage,
errorWithMultilineMarkerMessage',
errorWithSingleBlankMarker,
errorWithBlankAndNormalMarkerInLine,
beautifulExample
]
customAnnReports =
[ colorfulReport,
indentedReport,
nestingReport
]
let diag = HashMap.foldlWithKey' addFile (foldl addReport mempty reports) files
customDiag = HashMap.foldlWithKey' addFile (foldl addReport mempty customAnnReports) files
hPutStrLn stdout "\n\nWith unicode: ─────────────────────────\n"
printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle diag
hPutStrLn stdout "\n\nWithout unicode: ----------------------\n"
printDiagnostic stdout WithoutUnicode (TabSize 4) defaultStyle diag
hPutStrLn stdout "\n\nWith custom annotations: ----------------------\n"
printDiagnostic' stdout WithUnicode (TabSize 4) defaultStyle customDiag
#ifdef USE_AESON
hPutStrLn stdout "\n\nAs JSON: ------------------------------\n"
BS.hPutStr stdout (diagnosticToJson diag)
#endif
hPutStrLn stdout "\n"
colorfulReport :: Report (Doc AnsiStyle)
colorfulReport =
fmap hsep
. getCompose
. snd
. mapAccumL
(\(c : cs) s -> (cs, annotate c (pretty s)))
styles
. Compose
. fmap words
$ realWorldExample
where
styles = [ color fg <> e
| fg <- cycle [Black, Red, Green, Yellow, Blue, Magenta, Cyan, White]
| e <- cycle [bold, italicized, underlined]
]
indentedReport :: Report (Doc AnsiStyle)
indentedReport =
Err
Nothing
("Indent..." <> indent 3 (vsep ["foo", "bar", "baz"]))
[ (Position (1, 15) (1, 16) "test.zc", Maybe a)
, (Position (1, 11) (1, 12) "test.zc", This b)
]
[Note c]
where
a =
vsep
[ "A woman’s face with Nature’s own hand painted"
, "Hast thou, the master-mistress of my passion;"
, "A woman’s gentle heart, but not acquainted"
, "With shifting change, as is false women’s fashion;"
]
b =
vsep
[ "An eye more bright than theirs, less false in rolling,"
, "Gilding the object whereupon it gazeth;"
, "A man in hue, all “hues” in his controlling,"
, "Which steals men’s eyes and women’s souls amazeth."
]
c =
vsep
[ "And for a woman wert thou first created;"
, "Till Nature, as she wrought thee, fell a-doting,"
, "And by addition me of thee defeated,"
, "By adding one thing to my purpose nothing."
, indent 4 "But since she prick’d thee out for women’s pleasure,"
, indent 4 "Mine be thy love and thy love’s use their treasure."
]
nestingReport :: Report (Doc AnsiStyle)
nestingReport =
Err
Nothing
(nest 4 $ vsep ["Nest...", "foo", "bar", "baz"])
[ (Position (1, 15) (1, 16) "test.zc", Maybe a)
]
[Note b, Hint c]
where
a =
nest 3 $
vsep
[ "'What day is it?' asked Pooh."
, "'It's today,' squeaked Piglet."
, "'My favourite day,' said Pooh."
]
b =
foldr1
(\p q -> nest 2 (vsep [p, q]))
[ "It's a very funny thought that, if Bears were Bees,"
, "They'd build their nests at the bottom of trees."
, "And that being so (if the Bees were Bears),"
, "We shouldn't have to climb up all these stairs."
]
c =
"The elements:"
<+> align
( list
[ "antimony"
, "arsenic"
, "aluminum"
, "selenium"
, "hydrogen"
, "oxygen"
, "nitrogen"
, "rhenium"
, align $ reflow "And there may be many others, but they haven't been discovered"
]
)
errorNoMarkersNoHints :: Report String
errorNoMarkersNoHints =
Err
Nothing
"Error with no marker"
[]
[]
errorSingleMarkerNoHints :: Report String
errorSingleMarkerNoHints =
Err
Nothing
"Error with one marker in bounds"
[(Position (1, 25) (1, 30) "test.zc", This "Required here")]
[]
warningSingleMarkerNoHints :: Report String
warningSingleMarkerNoHints =
Warn
Nothing
"Warning with one marker in bounds"
[(Position (1, 25) (1, 30) "test.zc", This "Required here")]
[]
errorTwoMarkersSameLineNoOverlapNoHints :: Report String
errorTwoMarkersSameLineNoOverlapNoHints =
Err
Nothing
"Error with two markers in bounds (no overlap) on the same line"
[ (Position (1, 5) (1, 10) "test.zc", This "First"),
(Position (1, 15) (1, 22) "test.zc", Where "Second")
]
[]
errorSingleMarkerOutOfBoundsNoHints :: Report String
errorSingleMarkerOutOfBoundsNoHints =
Err
Nothing
"Error with one marker out of bounds"
[(Position (10, 5) (10, 15) "test2.zc", This "Out of bounds")]
[]
errorTwoMarkersSameLineOverlapNoHints :: Report String
errorTwoMarkersSameLineOverlapNoHints =
Err
Nothing
"Error with two overlapping markers in bounds"
[ (Position (1, 6) (1, 13) "test.zc", This "First"),
(Position (1, 10) (1, 15) "test.zc", Where "Second")
]
[]
errorTwoMarkersSameLinePartialOverlapNoHints :: Report String
errorTwoMarkersSameLinePartialOverlapNoHints =
Err
Nothing
"Error with two partially overlapping markers in bounds"
[ (Position (1, 5) (1, 25) "test.zc", This "First"),
(Position (1, 12) (1, 20) "test.zc", Where "Second")
]
[]
errorTwoMarkersTwoLinesNoHints :: Report String
errorTwoMarkersTwoLinesNoHints =
Err
Nothing
"Error with two markers on two lines in bounds"
[ (Position (1, 5) (1, 12) "test.zc", This "First"),
(Position (2, 3) (2, 4) "test.zc", Where "Second")
]
[]
realWorldExample :: Report String
realWorldExample =
Err
Nothing
"Could not deduce constraint 'Num(a)' from the current context"
[ (Position (1, 25) (1, 30) "test.zc", This "While applying function '+'"),
(Position (1, 11) (1, 16) "test.zc", Where "'x' is supposed to have type 'a'"),
(Position (1, 8) (1, 9) "test.zc", Where "type 'a' is bound here without constraints")
]
["Adding 'Num(a)' to the list of constraints may solve this problem."]
errorTwoMarkersSamePositionNoHints :: Report String
errorTwoMarkersSamePositionNoHints =
Err
Nothing
"Error with two markers on the same exact position in bounds"
[ (Position (1, 6) (1, 10) "test.zc", This "First"),
(Position (1, 6) (1, 10) "test.zc", Maybe "Second")
]
[]
errorThreeMarkersWithOverlapNoHints :: Report String
errorThreeMarkersWithOverlapNoHints =
Err
Nothing
"Error with three markers with overlapping in bounds"
[ (Position (1, 9) (1, 15) "test.zc", This "First"),
(Position (1, 9) (1, 18) "test.zc", Maybe "Second"),
(Position (1, 6) (1, 10) "test.zc", Where "Third")
]
[]
errorWithMultilineErrorNoMarkerNoHints :: Report String
errorWithMultilineErrorNoMarkerNoHints =
Err
Nothing
"Error with multi\nline message and no markers"
[]
[]
errorSingleMultilineMarkerMessageNoHints :: Report String
errorSingleMultilineMarkerMessageNoHints =
Err
Nothing
"Error with single marker with multiline message"
[(Position (1, 9) (1, 15) "test.zc", This "First\nmultiline")]
[]
errorTwoMarkersSameOriginOverlapNoHints :: Report String
errorTwoMarkersSameOriginOverlapNoHints =
Err
Nothing
"Error with two markers with same origin but partial overlap in bounds"
[ (Position (1, 9) (1, 15) "test.zc", This "First"),
(Position (1, 9) (1, 20) "test.zc", Maybe "Second")
]
[]
errorNoMarkersSingleHint :: Report String
errorNoMarkersSingleHint =
Err
Nothing
"Error with no marker and one hint"
[]
["First hint"]
errorNoMarkersSingleMultilineHint :: Report String
errorNoMarkersSingleMultilineHint =
Err
Nothing
"Error with no marker and one multiline hint"
[]
["First multi\nline hint"]
errorNoMarkersTwoHints :: Report String
errorNoMarkersTwoHints =
Err
Nothing
"Error with no markers and two hints"
[]
[ "First note",
Hint "Second hint"
]
errorSingleMultilineMarkerNoHints :: Report String
errorSingleMultilineMarkerNoHints =
Err
Nothing
"Error with single marker spanning across multiple lines"
[(Position (1, 15) (2, 6) "test.zc", This "First")]
[]
errorTwoMarkersWithMultilineNoHints :: Report String
errorTwoMarkersWithMultilineNoHints =
Err
Nothing
"Error with two markers, one single line and one multiline, in bounds"
[ (Position (1, 9) (1, 13) "test.zc", This "First"),
(Position (1, 14) (2, 6) "test.zc", Where "Second")
]
[]
errorTwoMultilineMarkersNoHints :: Report String
errorTwoMultilineMarkersNoHints =
Err
Nothing
"Error with two multiline markers in bounds"
[ (Position (1, 9) (2, 5) "test.zc", This "First"),
(Position (2, 1) (3, 10) "test.zc", Where "Second")
]
[]
errorSingleMultilineMarkerMultilineMessageNoHints :: Report String
errorSingleMultilineMarkerMultilineMessageNoHints =
Err
Nothing
"Error with one multiline marker with a multiline message in bounds"
[(Position (1, 9) (2, 5) "test.zc", This "Multi\nline message")]
[]
errorTwoMultilineMarkersFirstMultilineMessageNoHints :: Report String
errorTwoMultilineMarkersFirstMultilineMessageNoHints =
Err
Nothing
"Error with two multiline markers with one multiline message in bounds"
[ (Position (1, 9) (2, 5) "test.zc", This "First"),
(Position (1, 9) (2, 6) "test.zc", Where "Multi\nline message")
]
[]
errorThreeMultilineMarkersTwoMultilineMessageNoHints :: Report String
errorThreeMultilineMarkersTwoMultilineMessageNoHints =
Err
Nothing
"Error with three multiline markers with two multiline messages in bounds"
[ (Position (1, 9) (2, 5) "test.zc", This "First"),
(Position (1, 9) (2, 6) "test.zc", Where "Multi\nline message"),
(Position (1, 9) (2, 7) "test.zc", Maybe "Multi\nline message #2")
]
[]
errorOrderSensitive :: Report String
errorOrderSensitive =
Err
Nothing
"Order-sensitive labels with crossing"
[ (Position (1, 1) (1, 7) "somefile.zc", This "Leftmost label"),
(Position (1, 9) (1, 16) "somefile.zc", Where "Rightmost label")
]
[]
beautifulExample :: Report String
beautifulExample =
Err
Nothing
"Could not deduce constraint 'Num(a)' from the current context"
[ (Position (1, 25) (2, 6) "somefile.zc", This "While applying function '+'"),
(Position (1, 11) (1, 16) "somefile.zc", Where "'x' is supposed to have type 'a'"),
(Position (1, 8) (1, 9) "somefile.zc", Where "type 'a' is bound here without constraints")
]
["Adding 'Num(a)' to the list of constraints may solve this problem."]
errorMultilineAfterSingleLine :: Report String
errorMultilineAfterSingleLine =
Err
Nothing
"Multiline after single line"
[ (Position (1, 17) (1, 18) "unsized.nst", Where "Kind is infered from here"),
(Position (2, 14) (3, 0) "unsized.nst", This "is an error")
]
[]
errorOnEmptyLine :: Report String
errorOnEmptyLine =
Err
Nothing
"Error on empty line"
[(Position (1, 5) (3, 8) "err.nst", This "error on empty line")]
[]
errorMultipleFiles :: Report String
errorMultipleFiles =
Err
Nothing
"Error on multiple files"
[ (Position (1, 5) (1, 7) "test.zc", Where "Function already declared here"),
(Position (1, 5) (1, 7) "somefile.zc", This "Function `id` is already declared in another module")
]
[]
errorWithCode :: Report String
errorWithCode =
Err
(Just "E0123")
"Error with code and markers"
[(Position (1, 5) (1, 7) "test.zc", This "is an error")]
[]
errorWithStrangeUnicodeInput :: Report String
errorWithStrangeUnicodeInput =
Err
(Just "❎")
"ⓈⓉⓇⒶⓃⒼⒺ ⓊⓃⒾⒸⓄⒹⒺ"
[ (Position (1, 1) (1, 7) "unicode.txt", This "should work fine 🎉"),
(Position (1, 7) (1, 9) "unicode.txt", Where "After TAB")
]
[]
errorWithMultilineMarkerOn3Lines :: Report String
errorWithMultilineMarkerOn3Lines =
Err
Nothing
"Multiline marker on 3 lines"
[(Position (1, 3) (3, 10) "test.zc", This "should color all 3 lines correctly")]
[]
errorMultilineMarkerNotAtEnd :: Report String
errorMultilineMarkerNotAtEnd =
Err
Nothing
"Multiline marker not at end of report"
[ (Position (1, 10) (2, 3) "test.zc", This "is a multline marker"),
(Position (3, 5) (3, 13) "test.zc", Where "inline marker found after")
]
[]
errorWithLineGap :: Report String
errorWithLineGap =
Err
Nothing
"Error with line gaps between two markers"
[ (Position (1, 1) (1, 3) "gaps.txt", Where "is a first marker"),
(Position (5, 2) (5, 4) "gaps.txt", This "is the main marker")
]
[]
errorWithMultilineMarkerMessage :: Report String
errorWithMultilineMarkerMessage =
Err
Nothing
"Error with multiline message in first marker"
[ (Position (1, 5) (1, 10) "test.zc", This "First\nmarker"),
(Position (1, 15) (1, 22) "test.zc", Where "Second")
]
[]
errorWithMultilineMarkerMessage' :: Report String
errorWithMultilineMarkerMessage' =
Err
Nothing
"Error with multiline message in first marker"
[ (Position (1, 5) (1, 10) "test.zc", This "First\nmarker"),
(Position (1, 15) (1, 22) "test.zc", Where "Second"),
(Position (1, 10) (1, 15) "test.zc", Maybe "Third")
]
[]
repro3 :: Report String
repro3 =
Err
(Just "WrongStaticLayerLength")
"The length of the static layer does not match the length of the template it uses"
[ (Position (3, 3) (5, 16) "repro3.file", Where "This template has 9 elements"),
(Position (24, 28) (24, 39) "repro3.file", This "... but this layer only has 3 members"),
(Position (24, 21) (24, 26) "repro3.file", Where "This is the template being used"),
(Position (24, 7) (24, 15) "repro3.file", Where "while checking this static layer")
]
[]
errorWithSingleBlankMarker :: Report String
errorWithSingleBlankMarker =
Err
Nothing
"Error with a single blank marker"
[(Position (1, 5) (1, 10) "test.zc", Blank)]
[]
errorWithBlankAndNormalMarkerInLine :: Report String
errorWithBlankAndNormalMarkerInLine =
Err
Nothing
"Error with a single blank marker"
[(Position (1, 5) (1, 10) "test.zc", Blank), (Position (1, 15) (1, 22) "test.zc", This "After a blank")]
[]