forked from xodio/hm-parser
-
Notifications
You must be signed in to change notification settings - Fork 0
/
test.js
404 lines (346 loc) · 15.1 KB
/
test.js
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
var Tape = require('tape');
var HMP = require('../dist/index');
// Copy of tests as is from:
// https://github.com/kedashoe/hindley-milner-parser-js/blob/master/test/test.js
Tape.test('parse', t => {
t.deepEqual(
HMP.parse('hello :: a -> Maybe a'), {
name: 'hello',
constraints: [],
type:
{type: 'function', text: '', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typevar', text: 'a', children: []}]}]}
});
t.deepEqual(
HMP.parse('x :: [a] -> Integer'), {
name: 'x',
constraints: [],
type:
{type: 'function', text: '', children: [
{type: 'list', text: '', children: [
{type: 'typevar', text: 'a', children: []}]},
{type: 'typeConstructor', text: 'Integer', children: []}]}
});
t.deepEqual(
HMP.parse('hello :: a -> { x :: String, y :: a }'), {
name: 'hello',
constraints: [],
type:
{type: 'function', text: '', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'record', text: '', children: [
{type: 'field', text: 'x', children: [
{type: 'typeConstructor', text: 'String', children: []}]},
{type: 'field', text: 'y', children: [
{type: 'typevar', text: 'a', children: []}]}]}]}
});
t.deepEqual(
HMP.parse('Maybe#chain :: Maybe a ~> (a -> Maybe b) -> Maybe b'), {
name: 'Maybe#chain',
constraints: [],
type:
{type: 'method', text: '', children: [
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typevar', text: 'a', children:[]}]},
{type: 'function', text: '', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typevar', text: 'b', children: []}]}]},
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typevar', text: 'b', children: []}]}]}
});
t.deepEqual(
HMP.parse('hello :: Foo a => a -> String'), {
name: 'hello',
constraints: [
{typeclass: 'Foo', typevar: 'a'}],
type:
{type: 'function', text: '', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typeConstructor', text: 'String', children: []}]}});
t.deepEqual(
HMP.parse('reduce_ :: Foldable f => ((a, b) -> a) -> a -> f b -> a'), {
name: 'reduce_',
constraints: [
{typeclass: 'Foldable', typevar: 'f'}],
type:
{type: 'function', text: '', children: [
{type: 'uncurriedFunction', text: '', children: [
{type: 'parameters', text: '', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typevar', text: 'b', children: []}]},
{type: 'typevar', text: 'a', children: []}]},
{type: 'typevar', text: 'a', children: []},
{type: 'constrainedType', text: 'f', children: [
{type: 'typevar', text: 'b', children: []}]},
{type: 'typevar', text: 'a', children: []}]}});
t.deepEqual(
HMP.parse('hello :: (Foo f, Bar a) => (a -> f b) -> [a] -> [Either (Maybe a) b]'), {
name: 'hello',
constraints: [
{typeclass: 'Foo', typevar: 'f'},
{typeclass: 'Bar', typevar: 'a'}],
type:
{type: 'function', text: '', children: [
{type: 'function', text: '', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'constrainedType', text: 'f', children: [
{type: 'typevar', text: 'b', children: []}]}]},
{type: 'list', text: '', children: [
{type: 'typevar', text: 'a', children: []}]},
{type: 'list', text: '', children: [
{type: 'typeConstructor', text: 'Either', children: [
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typevar', text: 'a', children: []}]},
{type: 'typevar', text: 'b', children: []}]}]}]}});
t.deepEqual(
HMP.parse('sum :: Foldable f => f FiniteNumber -> FiniteNumber'), {
name: 'sum',
constraints: [
{typeclass: 'Foldable', typevar: 'f'}],
type:
{type: 'function', text: '', children: [
{type: 'constrainedType', text: 'f', children: [
{type: 'typeConstructor', text: 'FiniteNumber', children: []}]},
{type: 'typeConstructor', text: 'FiniteNumber', children: []}]}});
t.deepEqual(
HMP.parse('promap :: Profunctor p => (a -> b, c -> d, p b c) -> p a d'), {
name: 'promap',
constraints: [
{typeclass: 'Profunctor', typevar: 'p'}],
type:
{type: 'uncurriedFunction', text: '', children: [
{type: 'parameters', text: '', children: [
{type: 'function', text: '', children: [
{type: 'typevar', text: 'a', children:[]},
{type: 'typevar', text: 'b', children:[]}]},
{type: 'function', text: '', children: [
{type: 'typevar', text: 'c', children:[]},
{type: 'typevar', text: 'd', children:[]}]},
{type: 'constrainedType', text: 'p', children: [
{type: 'typevar', text: 'b', children:[]},
{type: 'typevar', text: 'c', children:[]}]}]},
{type: 'constrainedType', text: 'p', children: [
{type: 'typevar', text: 'a', children:[]},
{type: 'typevar', text: 'd', children:[]}]}]}});
t.deepEqual(
HMP.parse('maybe_ :: (() -> b) -> (a -> b) -> Maybe a -> b'), {
name: 'maybe_',
constraints: [],
type:
{type: 'function', text: '', children: [
{type: 'function', text: '', children: [
{type: 'thunk', text: '', children: []},
{type: 'typevar', text: 'b', children: []}]},
{type: 'function', text: '', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typevar', text: 'b', children: []}]},
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typevar', text: 'a', children: []}]},
{type: 'typevar', text: 'b', children: []}]}});
t.end();
});
Tape.test('name', t => {
t.deepEqual(HMP.name('foo'), 'foo');
t.deepEqual(HMP.name('foo\''), 'foo\'');
t.deepEqual(HMP.name('Maybe#@@type'),'Maybe#@@type');
t.end();
});
Tape.test('classConstraints', t => {
t.deepEqual(HMP.classConstraints('(Eq a, Foo b, Bar b)'), [
{typeclass: 'Eq', typevar: 'a'},
{typeclass: 'Foo', typevar: 'b'},
{typeclass: 'Bar', typevar: 'b'}]);
t.deepEqual(HMP.classConstraints('(Eq a, Foo b)'), [
{typeclass: 'Eq', typevar: 'a'},
{typeclass: 'Foo', typevar: 'b'}]);
t.deepEqual(HMP.classConstraints('Eq a'), [
{typeclass: 'Eq', typevar: 'a'}]);
t.end();
});
Tape.test('typevar', t => {
t.deepEqual(HMP.typevar('a'),
{type: 'typevar', text: 'a', children: []});
t.end();
});
Tape.test('thunk', t => {
t.deepEqual(HMP.thunk('() -> Maybe a'),
{type: 'function', text: '', children: [
{type: 'thunk', text: '', children: []},
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typevar', text: 'a', children: []}]}]});
t.deepEqual(HMP.thunk('() -> a'),
{type: 'function', text: '', children: [
{type: 'thunk', text: '', children: []},
{type: 'typevar', text: 'a', children: []}]});
t.end();
});
Tape.test('constrainedType', t => {
t.deepEqual(HMP.constrainedType('f a'),
{type: 'constrainedType', text: 'f', children: [
{type: 'typevar', text: 'a', children: []}]});
t.deepEqual(HMP.constrainedType('p a b'),
{type: 'constrainedType', text: 'p', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typevar', text: 'b', children: []}]});
t.deepEqual(HMP.constrainedType('f Integer'),
{type: 'constrainedType', text: 'f', children: [
{type: 'typeConstructor', text: 'Integer', children: []}]});
t.end();
});
Tape.test('record', t => {
t.deepEqual(HMP.record('{ foo :: Integer, bar :: Maybe [a] }'),
{type: 'record', text: '', children: [
{type: 'field', text: 'foo', children: [
{type: 'typeConstructor', text: 'Integer', children: []}]},
{type: 'field', text: 'bar', children: [
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'list', text: '', children: [
{type: 'typevar', text: 'a', children: []}]}]}]}]});
t.deepEqual(HMP.record('{ foo :: Integer }'),
{type: 'record', text: '', children: [
{type: 'field', text: 'foo', children: [
{type: 'typeConstructor', text: 'Integer', children: []}]}]});
t.end();
});
Tape.test('uncurriedFunction', t => {
t.deepEqual(HMP.uncurriedFunction('(a, b) -> Integer'),
{type: 'uncurriedFunction', text: '', children: [
{type: 'parameters', text: '', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typevar', text: 'b', children: []}]},
{type: 'typeConstructor', text: 'Integer', children: []}]});
t.deepEqual(HMP.uncurriedFunction('(Bool, [a], Maybe a) -> Either String a'),
{type: 'uncurriedFunction', text: '', children: [
{type: 'parameters', text: '', children: [
{type: 'typeConstructor', text: 'Bool', children: []},
{type: 'list', text: '', children: [
{type: 'typevar', text: 'a', children:[]}]},
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typevar', text: 'a', children:[]}]}]},
{type: 'typeConstructor', text: 'Either', children: [
{type: 'typeConstructor', text: 'String', children: []},
{type: 'typevar', text: 'a', children:[]}]}]});
t.end();
});
Tape.test('method', t => {
t.deepEqual(HMP.method('Foo ~> Integer'),
{type: 'method', text: '', children: [
{type: 'typeConstructor', text: 'Foo', children: []},
{type: 'typeConstructor', text: 'Integer', children: []}]});
t.deepEqual(HMP.method('Maybe a ~> b -> Boolean'),
{type: 'method', text: '', children: [
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typevar', text: 'a', children: []}]},
{type: 'typevar', text: 'b', children: []},
{type: 'typeConstructor', text: 'Boolean', children: []}]});
t.end();
});
Tape.test('function', t => {
t.deepEqual(HMP.fn('(a -> b) -> [a] -> [b]'),
{type: 'function', text: '', children: [
{type: 'function', text: '', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typevar', text: 'b', children: []}]},
{type: 'list', text: '', children: [
{type: 'typevar', text: 'a', children: []}]},
{type: 'list', text: '', children: [
{type: 'typevar', text: 'b', children: []}]}]});
t.deepEqual(HMP.fn('(a -> b) -> a -> b'),
{type: 'function', text: '', children: [
{type: 'function', text: '', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typevar', text: 'b', children: []}]},
{type: 'typevar', text: 'a', children: []},
{type: 'typevar', text: 'b', children: []}]});
t.deepEqual(HMP.fn('f a -> b'),
{type: 'function', text: '', children: [
{type: 'constrainedType', text: 'f', children: [
{type: 'typevar', text: 'a', children: []}]},
{type: 'typevar', text: 'b', children: []}]});
t.deepEqual(HMP.fn('a -> Boolean'),
{type: 'function', text: '', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typeConstructor', text: 'Boolean', children: []}]});
t.deepEqual(HMP.fn('Maybe a -> a'),
{type: 'function', text: '', children: [
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typevar', text: 'a', children: []}]},
{type: 'typevar', text: 'a', children: []}]});
t.deepEqual(HMP.fn('a -> b'),
{type: 'function', text: '', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typevar', text: 'b', children: []}]});
t.end();
});
Tape.test('list', t => {
t.deepEqual(HMP.list('[[Integer]]'),
{type: 'list', text: '', children: [
{type: 'list', text: '', children: [
{type: 'typeConstructor', text: 'Integer', children: []}]}]});
t.deepEqual(HMP.list('[a]'),
{type: 'list', text: '', children: [
{type: 'typevar', text: 'a', children: []}]});
t.deepEqual(HMP.list('[Maybe a]'),
{type: 'list', text: '', children: [
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typevar', text: 'a', children: []}]}]});
t.deepEqual(HMP.list('[a -> Bool]'),
{type: 'list', text: '', children: [
{type: 'function', text: '', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typeConstructor', text: 'Bool', children: []}]}]});
t.end();
});
Tape.test('typeConstructor', t => {
t.deepEqual(HMP.typeConstructor('Maybe (Either a (Maybe b))'),
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typeConstructor', text: 'Either', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typevar', text: 'b', children: []}]}]}]});
t.deepEqual(HMP.typeConstructor('Maybe (Either a b)'),
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typeConstructor', text: 'Either', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typevar', text: 'b', children: []}]}]});
t.deepEqual(HMP.typeConstructor('Maybe (f a)'),
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'constrainedType', text: 'f', children: [
{type: 'typevar', text: 'a', children: []}]}]});
t.deepEqual(HMP.typeConstructor('Maybe Integer'),
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typeConstructor', text: 'Integer', children: []}]});
t.deepEqual(HMP.typeConstructor('Either Integer Bool'),
{type: 'typeConstructor', text: 'Either', children: [
{type: 'typeConstructor', text: 'Integer', children: []},
{type: 'typeConstructor', text: 'Bool', children: []}]});
t.deepEqual(HMP.typeConstructor('Triple a (Maybe Bool) Integer'),
{type: 'typeConstructor', text: 'Triple', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typeConstructor', text: 'Bool', children: []}]},
{type: 'typeConstructor', text: 'Integer', children: []}]});
t.deepEqual(HMP.typeConstructor('Either a (f b)'),
{type: 'typeConstructor', text: 'Either', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'constrainedType', text: 'f', children: [
{type: 'typevar', text: 'b', children: []}]}]});
t.deepEqual(HMP.typeConstructor('Either a b'),
{type: 'typeConstructor', text: 'Either', children: [
{type: 'typevar', text: 'a', children: []},
{type: 'typevar', text: 'b', children: []}]});
t.deepEqual(HMP.typeConstructor('Maybe a'),
{type: 'typeConstructor', text: 'Maybe', children: [
{type: 'typevar', text: 'a', children: []}]});
t.deepEqual(HMP.typeConstructor('A b'),
{type: 'typeConstructor', text: 'A', children: [
{type: 'typevar', text: 'b', children: []}]});
t.deepEqual(HMP.typeConstructor('Bool'),
{type: 'typeConstructor', text: 'Bool', children: []});
t.deepEqual(HMP.typeConstructor('A'),
{type: 'typeConstructor', text: 'A', children: []});
t.end();
});