aa
TestHM8.java
Go to the documentation of this file.
1 package com.cliffc.aa.HM;
2 
3 import com.cliffc.aa.HM.HM8.*;
4 import org.junit.Before;
5 import org.junit.Test;
6 
7 import static org.junit.Assert.assertEquals;
8 
9 public class TestHM8 {
10 
11  @Before public void reset() { HM8.reset(); }
12 
13  @Test(expected = RuntimeException.class)
14  public void test00() {
15  HM8.hm("fred");
16  }
17 
18  @Test
19  public void test01() {
20  Syntax syn = HM8.hm("3");
21  assertEquals("3",syn._t.p());
22  assertEquals("[]",syn._post.p());
23  }
24 
25  @Test
26  public void test02() {
27  Syntax syn = HM8.hm("(pair1 3)");
28  assertEquals("{ A -> (pair 3 A) }",syn._t.p());
29  assertEquals("[]",syn._post.p());
30  }
31 
32  @Test
33  public void test03() {
34  Syntax syn = HM8.hm("{ z -> (pair (z 3) (z \"abc\")) }");
35  assertEquals("{ { all -> A } -> (pair A A) }",syn._t.p());
36  assertEquals("[]",syn._post.p());
37  }
38 
39  @Test
40  public void test04() {
41  Syntax syn = HM8.hm("fact = { n -> (if (?0 n) 1 (* n (fact (dec n))))}; fact");
42  assertEquals("{ int64 -> int64 }",syn._t.p());
43  assertEquals("[]",syn._post.p());
44  }
45 
46  @Test
47  public void test05a() {
48  Syntax syn = HM8.hm("id={x->x}; (pair (id 3) (id \"abc\"))");
49  assertEquals("(pair 3 \"abc\")",syn._t.p());
50  assertEquals("[]",syn._post.p());
51  }
52 
53  @Test
54  public void test05() {
55  // Because {y->y} is passed in, all 'y' types must agree.
56  // This unifies 3 and "abc" which results in 'all'
57  Syntax syn = HM8.hm("({ x -> (pair (x 3) (x \"abc\")) } {y->y})");
58  assertEquals("(pair all all)",syn._t.p());
59  assertEquals("[]",syn._post.p());
60  }
61 
62  @Test//(expected = RuntimeException.class) No longer throws, but returns a recursive type
63  public void test06() {
64  // recursive unification
65  Syntax syn = HM8.hm("{ f -> (f f) }");
66  assertEquals("{ A:{ $A -> B } -> B }",syn._t.p());
67  assertEquals("[]",syn._post.p());
68  // We can argue the pretty-print should print:
69  // "A:{ $A -> B }"
70  }
71 
72  @Test
73  public void test07() {
74  Syntax syn = HM8.hm("g = {f -> 5}; (g g)");
75  assertEquals("5",syn._t.p());
76  assertEquals("[]",syn._post.p());
77  }
78 
79  @Test
80  public void test08() {
81  // example that demonstrates generic and non-generic variables:
82  Syntax syn = HM8.hm("{ g -> f = { x -> g }; (pair (f 3) (f \"abc\"))}");
83  assertEquals("{ A -> (pair A A) }",syn._t.p());
84  assertEquals("[]",syn._post.p());
85  }
86 
87  @Test
88  public void test09() {
89  Syntax syn = HM8.hm("{ f g -> (f g)}");
90  assertEquals("{ { A -> B } A -> B }",syn._t.p());
91  assertEquals("[]",syn._post.p());
92  }
93 
94  @Test
95  public void test10() {
96  // Function composition
97  Syntax syn = HM8.hm("{ f g -> { arg -> (g (f arg))} }");
98  assertEquals("{ { A -> B } { B -> C } -> { A -> C } }",syn._t.p());
99  assertEquals("[]",syn._post.p());
100  }
101 
102  @Test
103  public void test11() {
104  // Stacked functions ignoring all function arguments
105  Syntax syn = HM8.hm("map = { fun -> { x -> 2 } }; ((map 3) 5)");
106  assertEquals("2",syn._t.p());
107  assertEquals("[]",syn._post.p());
108  }
109 
110  @Test
111  public void test12() {
112  // map takes a function and an element (collection?) and applies it (applies to collection?)
113  Syntax syn = HM8.hm("map = { fun -> { x -> (fun x)}}; { p -> 5 }");
114  assertEquals("{ A -> 5 }",syn._t.p());
115  assertEquals("[]",syn._post.p());
116  }
117 
118  @Test
119  public void test13() {
120  // Looking at when tvars are duplicated ("fresh" copies made).
121  // This is the "map" problem with a scalar instead of a collection.
122  // Takes a '{a->b}' and a 'a' for a couple of different prims.
123  Syntax syn = HM8.hm("map = { fun -> { x -> (fun x)}};"+
124  "(pair ((map str) 5) ((map factor) 2.3))");
125  assertEquals("(pair str (divmod flt64 flt64))",syn._t.p());
126  assertEquals("[]",syn._post.p());
127  }
128 
129  @Test
130  public void test14() {
131  // map takes a function and an element (collection?) and applies it (applies to collection?)
132  Syntax syn = HM8.hm("map = { fun x -> (fun x)}; (map {a->3} 5)");
133  assertEquals("3",syn._t.p());
134  assertEquals("[]",syn._post.p());
135  }
136 
137  @Test
138  public void test15() {
139  // map takes a function and an element (collection?) and applies it (applies to collection?)
140  Syntax syn = HM8.hm("map = { fun x -> (fun x)}; (map { a-> (pair a a)} 5)");
141  assertEquals("(pair 5 5)",syn._t.p());
142  assertEquals("[]",syn._post.p());
143  }
144 
145  @Test
146  public void test16() {
147  Syntax syn = HM8.hm("fcn = { p -> { a -> (pair a a) }};"+
148  "map = { fun x -> (fun x)};"+
149  "{ q -> (map (fcn q) 5)}");
150  assertEquals("{ A -> (pair 5 5) }",syn._t.p());
151  assertEquals("[]",syn._post.p());
152  }
153 
154  @Test
155  public void test17() {
156  // Checking behavior when using "if" to merge two functions with
157  // sufficiently different signatures, then attempting to pass them to a map
158  // & calling internally.
159  // fcn takes a predicate 'p' and returns one of two fcns.
160  // let fcn = { p -> (if p {a -> pair[a,a ]}
161  // {b -> pair[b,pair[3,b]]}) } in
162  // map takes a function and an element (collection?) and applies it (applies to collection?)
163  // let map = { fun x -> (fun x) }
164  // in { q -> ((map (fcn q)) 5) }
165  // Should return { q -> q ? [5,5] : [5,[3,5]] }
166  // Ultimately, unifies "a" with "pair[3,a]" which throws recursive unification.
167  Syntax syn = HM8.hm("fcn = {p -> (if p {a -> (pair a a)} {b -> (pair b (pair 3 b))})};"+
168  "map = { fun x -> (fun x)};"+
169  "{ q -> (map (fcn q) 5)}");
170  assertEquals("{ A -> (pair Cannot unify $V123:(pair 3 $V123) and 5 Cannot unify $V123:(pair 3 $V123) and 5) }",syn._t.p());
171  assertEquals("[]",syn._post.p());
172  }
173 
174  @Test
175  public void test18() {
176  Syntax syn = HM8.hm("cons ={x y-> {cadr -> (cadr x y)}};"+
177  "cdr ={mycons -> (mycons { p q -> q})};"+
178  "(cdr (cons 2 3))");
179  assertEquals("3",syn._t.p());
180  assertEquals("[]",syn._post.p());
181  }
182 
183  // Take 2nd element of pair, and applies a function.
184  // let map = fn parg fun => (fun (cdr parg))
185  // Some pairs:
186  // let intz = (pair2 false 3)
187  // let strz = (pair2 false "abc")
188  // in pair(map(str,intz),map(isempty,strz))
189  // Expects: ("2",false)
190  @Test
191  public void test19() {
192  Syntax syn = HM8.hm("cons ={x y-> {cadr -> (cadr x y)}};"+
193  "cdr ={mycons -> (mycons { p q -> q})};"+
194  "map ={fun parg -> (fun (cdr parg))};"+
195  "(pair (map str (cons 0 5)) (map isempty (cons 0 \"abc\")))"
196  );
197  assertEquals("(pair str int1)",syn._t.p());
198  assertEquals("[]",syn._post.p());
199  }
200 
201  // Obscure factorial-like
202  @Test
203  public void test20() {
204  Syntax syn = HM8.hm("f0 = { f x -> (if (?0 x) 1 (f (f0 f (dec x)) 2))}; (f0 * 99)");
205  assertEquals("int64",syn._t.p());
206  assertEquals("[]",syn._post.p());
207  }
208 
209  // Obscure factorial-like
210  @Test
211  public void test21() {
212  // let f0 = fn f x => (if (?0 x) 1 (* (f0 f (dec x)) 2) ) in f0 f0 99
213  // let f0 = fn f x => (if (?0 x) 1 (f (f0 f (dec x)) 2) ) in f0 * 99
214  Syntax syn = HM8.hm("f0 = { f x -> (if (?0 x) 1 (* (f0 f (dec x)) 2))}; (f0 f0 99)");
215  assertEquals("int64",syn._t.p());
216  assertEquals("[]",syn._post.p());
217  }
218 
219  // Mutual recursion
220  @Test
221  public void test22() {
222  Syntax syn = HM8.hm("is_even = "+
223  " is_odd = { n -> (if (?0 n) 0 (is_even (dec n)))}; "+
224  " { n -> (if (?0 n) 1 (is_odd (dec n)))};"+
225  "(is_even 3)"
226  );
227  assertEquals("int1",syn._t.p());
228  assertEquals("[]",syn._post.p());
229  }
230 
231  // Toss a function into a pair & pull it back out
232  @Test
233  public void test23() {
234  Syntax syn = HM8.hm("{ g -> fgz = "+
235  " cons = {x y -> {cadr -> (cadr x y)}};"+
236  " cdr = {mycons -> (mycons { p q -> q})};"+
237  " (cdr (cons 2 { z -> (g z) }));"+
238  " (pair (fgz 3) (fgz 5))"+
239  "}"
240  );
241  assertEquals("{ { nint8 -> A } -> (pair A A) }",syn._t.p());
242  assertEquals("[]",syn._post.p());
243  }
244 
245  // Basic structure test
246  @Test
247  public void test24() {
248  Syntax syn = HM8.hm("@{x=2, y=3}");
249  assertEquals("*[7]@{ x = 2, y = 3}",syn._t.p());
250  assertEquals("[ 7:*[7]@{ x = 2, y = 3}]",syn._post.p());
251  }
252 
253  // Basic field test
254  @Test
255  public void test25() {
256  Syntax syn = HM8.hm(".x @{x =2, y =3}");
257  assertEquals("2",syn._t.p());
258  assertEquals("[ 7:*[7]@{ x = 2, y = 3}]",syn._post.p());
259  }
260 
261  // Basic field test
262  @Test
263  public void test25a() {
264  Syntax syn = HM8.hm(".x 5");
265  assertEquals("Cannot unify *[-2]@{ x = V24} and 5",syn._t.p());
266  assertEquals("[]",syn._post.p());
267  }
268 
269  // Basic field test.
270  @Test
271  public void test25b() {
272  Syntax syn = HM8.hm(".x @{ y =3}");
273  assertEquals("Missing field x in *[7]@{ y = 3, x = all}",syn._t.p());
274  assertEquals("[ 7:*[7]@{ y = 3, x = Missing field x in *[7]@{ y = 3, x = all}}]",syn._post.p());
275  }
276 
277  @Test
278  public void test26() {
279  Syntax syn = HM8.hm("{ g -> @{x=g, y=g}}");
280  assertEquals("{ A -> *[7]@{ x = A, y = A} }",syn._t.p());
281  assertEquals("[ 7:*[7]@{ x = A, y = A}]",syn._post.p());
282  }
283 
284  @Test
285  public void test27() {
286  // Load common field 'x', ignoring mismatched fields y and z
287  Syntax syn = HM8.hm("{ pred -> .x (if pred @{x=2,y=3} @{x=3,z= \"abc\"}) }");
288  assertEquals("{ A -> nint8 }",syn._t.p());
289  assertEquals("[ 7:A:*[7,8]@{ x = nint8, z = all, y = all}, 8:$A]",syn._post.p());
290  }
291 
292  @Test
293  public void test28() {
294  // Load some fields from an unknown struct: area of a square.
295  // Since no nil-check, correctly types as needing a not-nil input.
296  Syntax syn = HM8.hm("{ sq -> (* .x sq .y sq) }"); // { sq -> sq.x * sq.y }
297  assertEquals("{ *[-2]@{ y = int64, x = int64} -> int64 }",syn._t.p());
298  assertEquals("[]",syn._post.p());
299  }
300 
301  @Test
302  public void test29() {
303  // Recursive linked-list discovery, with no end clause
304  Syntax syn = HM8.hm("map = { fcn lst -> @{ n1 = (map fcn .n0 lst), v1 = (fcn .v0 lst) } }; map");
305  assertEquals("{ { A -> B } C:*[-2]@{ v0 = A, n0 = $C} -> D:*[7]@{ n1 = $D, v1 = B} }",syn._t.p());
306  assertEquals("[ 7:A:*[7]@{ n1 = $A, v1 = B}]",syn._post.p());
307  }
308 
309  @Test
310  public void test30() {
311  // Recursive linked-list discovery, with nil. Note that the output memory
312  // has the output memory alias, but not the input memory alias (which must
313  // be made before calling 'map').
314  Syntax syn = HM8.hm("map = { fcn lst -> (if lst @{ n1=(map fcn .n0 lst), v1=(fcn .v0 lst) } nil) }; map");
315  assertEquals("{ { A -> B } C:*[-2]@{ v0 = A, n0 = $C}? -> D:*[7]@{ n1 = $D, v1 = B}? }",syn._t.p());
316  assertEquals("[ 7:A:*[7]@{ n1 = $A, v1 = B}?]",syn._post.p());
317  }
318 
319  @Test
320  public void test30a() {
321  // Recursive linked-list discovery, with no end clause
322  Syntax syn = HM8.hm("map = { fcn lst -> (if lst @{ n1 = (map fcn .n0 lst), v1 = (fcn .v0 lst) } nil) }; (map dec @{n0 = nil, v0 = 5})");
323  assertEquals("A:*[7]@{ n1 = $A, v1 = int64}?",syn._t.p());
324  assertEquals("[ 7:A:*[7]@{ n1 = $A, v1 = B}?, 8:*[8]@{ n0 = (Nil), v0 = int64}?]",syn._post.p());
325  }
326 
327  // try the worse-case expo blow-up test case from SO
328  @Test
329  public void test31() {
330  // Recursive linked-list discovery, with nil
331  Syntax syn = HM8.hm("p0 = { x y z -> (triple x y z) };"+
332  "p1 = (triple p0 p0 p0);"+
333  "p2 = (triple p1 p1 p1);"+
334  "p3 = (triple p2 p2 p2);"+
335  "p3");
336  assertEquals("(triple (triple (triple { A B C -> (triple A B C) } { D E F -> (triple D E F) } { G H I -> (triple G H I) }) (triple { J K L -> (triple J K L) } { M N O -> (triple M N O) } { P Q R -> (triple P Q R) }) (triple { S T U -> (triple S T U) } { V21 V22 V23 -> (triple V21 V22 V23) } { V24 V25 V26 -> (triple V24 V25 V26) })) (triple (triple { V27 V28 V29 -> (triple V27 V28 V29) } { V30 V31 V32 -> (triple V30 V31 V32) } { V33 V34 V35 -> (triple V33 V34 V35) }) (triple { V36 V37 V38 -> (triple V36 V37 V38) } { V39 V40 V41 -> (triple V39 V40 V41) } { V42 V43 V44 -> (triple V42 V43 V44) }) (triple { V45 V46 V47 -> (triple V45 V46 V47) } { V48 V49 V50 -> (triple V48 V49 V50) } { V51 V52 V53 -> (triple V51 V52 V53) })) (triple (triple { V54 V55 V56 -> (triple V54 V55 V56) } { V57 V58 V59 -> (triple V57 V58 V59) } { V60 V61 V62 -> (triple V60 V61 V62) }) (triple { V63 V64 V65 -> (triple V63 V64 V65) } { V66 V67 V68 -> (triple V66 V67 V68) } { V69 V70 V71 -> (triple V69 V70 V71) }) (triple { V72 V73 V74 -> (triple V72 V73 V74) } { V75 V76 V77 -> (triple V75 V76 V77) } { V78 V79 V80 -> (triple V78 V79 V80) })))",syn._t.p());
337  assertEquals("[]",syn._post.p());
338  }
339 
340  // Need to see if a map call, inlined a few times, 'rolls up'. Sometimes
341  // rolls up, sometimes not; depends on worklist visitation order.
342  @Test
343  public void test32() {
344  // Recursive linked-list discovery, with nil. Unrolled once.
345  Syntax syn = HM8.hm("map = { lst -> (if lst @{ n1= arg= .n0 lst; (if arg @{ n1=(map .n0 arg), v1=(str .v0 arg)} nil), v1=(str .v0 lst) } nil) }; map");
346  assertEquals("{ A:*[-2]@{ v0 = int64, n0 = *[-2]@{ n0 = $A, v0 = int64}?}? -> B:*[8]@{ n1 = *[7]@{ n1 = $B, v1 = str}?, v1 = str}? }",syn._t.p());
347  assertEquals("[ 7:A:*[7]@{ n1 = B:*[8]@{ n1 = $A, v1 = str}?, v1 = str}?, 8:$B]",syn._post.p());
348  }
349 
350  @Test
351  public void test33() {
352  Syntax syn = HM8.hm("x = { y -> (x (y y))}; x");
353  assertEquals("{ A:{ $A -> $A } -> B }",syn._t.p());
354  assertEquals("[]",syn._post.p());
355  }
356 
357  @Test
358  public void test34() {
359  // Example from SimpleSub requiring 'x' to be both a struct with field
360  // 'v', and also a function type - specifically disallowed in 'aa'.
361  Syntax syn = HM8.hm("{ x -> y = ( x .v x ); 0}");
362  assertEquals("{ Cannot unify *[-2]@{ v = V40} and { V40 -> V34 } -> 0 }",syn._t.p());
363  assertEquals("[]",syn._post.p());
364  }
365 
366  @Test
367  public void test35() {
368  Syntax syn = HM8.hm("x = { z -> z}; (x { y -> .u y})");
369  assertEquals("{ *[-2]@{ u = A} -> A }",syn._t.p());
370  assertEquals("[]",syn._post.p());
371  }
372 
373  @Test
374  public void test36() {
375  // Example from SimpleSub requiring 'x' to be both:
376  // - a recursive self-call function from "w = (x x)": $V66:{ $V66 -> V67 } AND
377  // - a function which takes a struct with field 'u'
378  // The first arg to x is two different kinds of functions, so fails unification.
379  Syntax syn = HM8.hm("x = w = (x x); { z -> z}; (x { y -> .u y})");
380  assertEquals("Cannot unify $V66:{ $V66 -> V67 } and *[-2]@{ u = V39}",syn._t.p());
381  assertEquals("[]",syn._post.p());
382  }
383 
384 }
com.cliffc.aa.HM.TestHM8.test14
void test14()
Definition: TestHM8.java:130
com.cliffc.aa.HM.TestHM8.reset
void reset()
Definition: TestHM8.java:11
com.cliffc.aa.HM.TestHM8.test31
void test31()
Definition: TestHM8.java:329
com.cliffc.aa.HM.TestHM8.test22
void test22()
Definition: TestHM8.java:221
com.cliffc.aa.HM.TestHM8.test01
void test01()
Definition: TestHM8.java:19
com.cliffc.aa.HM.TestHM8.test02
void test02()
Definition: TestHM8.java:26
com.cliffc
com.cliffc.aa.HM.TestHM8.test11
void test11()
Definition: TestHM8.java:103
com.cliffc.aa.HM.TestHM8.test19
void test19()
Definition: TestHM8.java:191
com.cliffc.aa.HM.TestHM8.test12
void test12()
Definition: TestHM8.java:111
com.cliffc.aa.HM.HM8.reset
static void reset()
Definition: HM8.java:86
com.cliffc.aa.HM.TestHM8.test15
void test15()
Definition: TestHM8.java:138
com.cliffc.aa.HM.TestHM8.test21
void test21()
Definition: TestHM8.java:211
com.cliffc.aa.HM.TestHM8.test18
void test18()
Definition: TestHM8.java:175
com.cliffc.aa.HM.TestHM8.test35
void test35()
Definition: TestHM8.java:367
com.cliffc.aa.HM.TestHM8.test29
void test29()
Definition: TestHM8.java:302
com.cliffc.aa.HM.TestHM8.test25a
void test25a()
Definition: TestHM8.java:263
com.cliffc.aa.HM.TestHM8.test23
void test23()
Definition: TestHM8.java:233
com.cliffc.aa.HM.HM8
Definition: HM8.java:24
com.cliffc.aa.HM.TestHM8.test13
void test13()
Definition: TestHM8.java:119
com.cliffc.aa.HM.TestHM8.test04
void test04()
Definition: TestHM8.java:40
com.cliffc.aa.HM.TestHM8.test27
void test27()
Definition: TestHM8.java:285
com.cliffc.aa.HM.TestHM8.test07
void test07()
Definition: TestHM8.java:73
com.cliffc.aa.HM.TestHM8.test34
void test34()
Definition: TestHM8.java:358
com.cliffc.aa.HM.TestHM8.test25
void test25()
Definition: TestHM8.java:255
com.cliffc.aa.HM.TestHM8.test26
void test26()
Definition: TestHM8.java:278
com.cliffc.aa.HM.TestHM8.test09
void test09()
Definition: TestHM8.java:88
com.cliffc.aa.HM.TestHM8.test06
void test06()
Definition: TestHM8.java:63
com.cliffc.aa.HM.TestHM8.test36
void test36()
Definition: TestHM8.java:374
com.cliffc.aa.HM.TestHM8.test03
void test03()
Definition: TestHM8.java:33
com.cliffc.aa.HM.TestHM8.test00
void test00()
Definition: TestHM8.java:14
com.cliffc.aa.HM.TestHM8.test30a
void test30a()
Definition: TestHM8.java:320
com.cliffc.aa.HM.TestHM8.test17
void test17()
Definition: TestHM8.java:155
com.cliffc.aa.HM.TestHM8.test16
void test16()
Definition: TestHM8.java:146
com.cliffc.aa.HM.TestHM8.test30
void test30()
Definition: TestHM8.java:310
com.cliffc.aa.HM.TestHM8.test24
void test24()
Definition: TestHM8.java:247
com.cliffc.aa.HM.TestHM8.test20
void test20()
Definition: TestHM8.java:203
com.cliffc.aa.HM.TestHM8.test33
void test33()
Definition: TestHM8.java:351
com.cliffc.aa
Definition: AA.java:1
com.cliffc.aa.HM.TestHM8.test28
void test28()
Definition: TestHM8.java:293
com.cliffc.aa.HM.TestHM8.test25b
void test25b()
Definition: TestHM8.java:271
com.cliffc.aa.HM.HM8.hm
static Syntax hm(String sprog)
Definition: HM8.java:29
com.cliffc.aa.HM
Definition: HM.java:1
com.cliffc.aa.HM.TestHM8
Definition: TestHM8.java:9
com.cliffc.aa.HM.TestHM8.test10
void test10()
Definition: TestHM8.java:95
com.cliffc.aa.HM.TestHM8.test32
void test32()
Definition: TestHM8.java:343
com.cliffc.aa.HM.TestHM8.test05a
void test05a()
Definition: TestHM8.java:47
com
com.cliffc.aa.HM.TestHM8.test08
void test08()
Definition: TestHM8.java:80
com.cliffc.aa.HM.TestHM8.test05
void test05()
Definition: TestHM8.java:54