|
3 | 3 |
|
4 | 4 | **CAUTION**: Experimental, **not** recommended for use in production code.""" |
5 | 5 |
|
6 | | -# Use "with show_expanded:" to see what it did. |
7 | | -#from macropy.tracing import macros, show_expanded |
| 6 | +from ...syntax import macros, test, test_raises # noqa: F401 |
| 7 | +from ...test.fixtures import testset, returns_normally |
8 | 8 |
|
9 | | -from ...syntax import macros, prefix, q, u, kw, curry, let, do # noqa: F401 |
| 9 | +from ...syntax import macros, prefix, q, u, kw, curry, let, do # noqa: F401, F811 |
10 | 10 |
|
11 | 11 | from ...fold import foldr |
12 | 12 | from ...fun import composerc as compose, apply |
13 | 13 | from ...llist import cons, nil, ll |
14 | 14 |
|
| 15 | +# Use "with show_expanded:" to see what it did. |
| 16 | +#from macropy.tracing import macros, show_expanded |
| 17 | + |
15 | 18 | def runtests(): |
16 | | - with prefix: |
17 | | - (print, "hello world") |
18 | | - x = 42 # can write any regular Python, too |
19 | | - |
20 | | - # quote operator q locally turns off the function-call transformation: |
21 | | - t1 = (q, 1, 2, (3, 4), 5) # q takes effect recursively |
22 | | - t2 = (q, 17, 23, x) # unlike in Lisps, x refers to its value even in a quote |
23 | | - (print, t1, t2) |
24 | | - |
25 | | - # unquote operator u locally turns the transformation back on: |
26 | | - t3 = (q, (u, print, 42), (print, 42), "foo", "bar") |
27 | | - assert t3 == (q, None, (print, 42), "foo", "bar") |
28 | | - |
29 | | - # quotes nest; call transformation made when quote level == 0 |
30 | | - t4 = (q, (print, 42), (q, (u, u, print, 42)), "foo", "bar") |
31 | | - assert t4 == (q, (print, 42), (None,), "foo", "bar") |
32 | | - |
33 | | - # Be careful: |
34 | | - try: |
35 | | - (x,) # in a prefix block, this means "call the 0-arg function x" |
36 | | - except TypeError: |
37 | | - pass # 'int' object is not callable |
38 | | - else: |
39 | | - assert False, "should have attempted to call x" |
40 | | - (q, x) # OK! |
41 | | - |
42 | | - # give named args with kw(...) [it's syntax, not really a function!]: |
43 | | - def f(*, a, b): |
44 | | - return (q, a, b) |
45 | | - # in one kw(...), or... |
46 | | - assert (f, kw(a="hi there", b="foo")) == (q, "hi there", "foo") |
47 | | - # in several kw(...), doesn't matter |
48 | | - assert (f, kw(a="hi there"), kw(b="foo")) == (q, "hi there", "foo") |
49 | | - # in case of duplicate name across kws, rightmost wins |
50 | | - assert (f, kw(a="hi there"), kw(b="foo"), kw(b="bar")) == (q, "hi there", "bar") |
51 | | - |
52 | | - # give *args with unpythonic.fun.apply, like in Lisps: |
53 | | - lst = [1, 2, 3] |
54 | | - def g(*args, **kwargs): |
55 | | - return args + tuple(sorted(kwargs.items())) |
56 | | - assert (apply, g, lst) == (q, 1, 2, 3) |
57 | | - # lst goes last; may have other args first |
58 | | - assert (apply, g, "hi", "ho", lst) == (q, "hi", "ho", 1, 2, 3) |
59 | | - # named args in apply are also fine |
60 | | - assert (apply, g, "hi", "ho", lst, kw(myarg=4)) == (q, "hi", "ho", 1, 2, 3, ('myarg', 4)) |
61 | | - |
62 | | - # Function call transformation only applies to tuples in load context |
63 | | - # (i.e. NOT on the LHS of an assignment) |
64 | | - a, b = (q, 100, 200) |
65 | | - assert a == 100 and b == 200 |
66 | | - a, b = (q, b, a) # pythonic swap in prefix syntax; must quote RHS |
67 | | - assert a == 200 and b == 100 |
68 | | - |
69 | | - # prefix leaves alone the let binding syntax ((name0, value0), ...) |
70 | | - a = let((x, 42))[x << x + 1] |
71 | | - assert a == 43 |
72 | | - |
73 | | - # but the RHSs of the bindings are transformed normally: |
74 | | - def double(x): |
75 | | - return 2 * x |
76 | | - a = let((x, (double, 21)))[x << x + 1] |
77 | | - assert a == 43 |
78 | | - |
79 | | - # similarly, prefix leaves the "body tuple" of a do alone |
80 | | - # (syntax, not semantically a tuple), but recurses into it: |
81 | | - a = do[1, 2, 3] |
82 | | - assert a == 3 |
83 | | - a = do[1, 2, (double, 3)] |
84 | | - assert a == 6 |
85 | | - |
86 | | - # the extra bracket syntax has no danger of confusion, as it's a list, not tuple |
87 | | - a = let((x, 3))[[ |
88 | | - 1, |
89 | | - 2, |
90 | | - (double, x)]] |
91 | | - assert a == 6 |
92 | | - |
93 | | - # Introducing the LisThEll programming language: an all-in-one solution with |
94 | | - # the prefix syntax of Lisp, the speed of Python, and the readability of Haskell! |
95 | | - with prefix, curry: |
96 | | - mymap = lambda f: (foldr, (compose, cons, f), nil) |
97 | | - double = lambda x: 2 * x |
98 | | - (print, (mymap, double, (q, 1, 2, 3))) |
99 | | - assert (mymap, double, (q, 1, 2, 3)) == ll(2, 4, 6) |
100 | | - |
101 | | - print("All tests PASSED") |
| 19 | + with testset("unpythonic.syntax.prefix"): |
| 20 | + with prefix: |
| 21 | + (print, "hello world") |
| 22 | + x = 42 # can write any regular Python, too |
| 23 | + |
| 24 | + with testset("quote operator"): |
| 25 | + # quote operator q locally turns off the function-call transformation: |
| 26 | + t1 = (q, 1, 2, (3, 4), 5) # q takes effect recursively |
| 27 | + t2 = (q, 17, 23, x) # unlike in Lisps, x refers to its value even in a quote |
| 28 | + (print, t1, t2) |
| 29 | + |
| 30 | + # unquote operator u locally turns the transformation back on: |
| 31 | + t3 = (q, (u, print, 42), (print, 42), "foo", "bar") |
| 32 | + test[t3 == (q, None, (print, 42), "foo", "bar")] |
| 33 | + |
| 34 | + # quotes nest; call transformation made when quote level == 0 |
| 35 | + t4 = (q, (print, 42), (q, (u, u, print, 42)), "foo", "bar") |
| 36 | + test[t4 == (q, (print, 42), (None,), "foo", "bar")] |
| 37 | + |
| 38 | + with testset("tuple in load context denotes a call"): |
| 39 | + # Be careful: |
| 40 | + test_raises[TypeError, |
| 41 | + (x,), # in a prefix block, this 1-element tuple means "call the 0-arg function x" |
| 42 | + "should have attempted to call x"] |
| 43 | + |
| 44 | + test[returns_normally((q, x))] # quoted, OK! |
| 45 | + |
| 46 | + # Function call transformation only applies to tuples in load context |
| 47 | + # (i.e. NOT on the LHS of an assignment) |
| 48 | + a, b = (q, 100, 200) |
| 49 | + test[a == 100 and b == 200] |
| 50 | + a, b = (q, b, a) # pythonic swap in prefix syntax; must quote RHS |
| 51 | + test[a == 200 and b == 100] |
| 52 | + |
| 53 | + with testset("kwargs"): |
| 54 | + # give named args with kw(...) [it's syntax, not really a function!]: |
| 55 | + def f(*, a, b): |
| 56 | + return (q, a, b) |
| 57 | + # in one kw(...), or... |
| 58 | + test[(f, kw(a="hi there", b="foo")) == (q, "hi there", "foo")] |
| 59 | + # in several kw(...), doesn't matter |
| 60 | + test[(f, kw(a="hi there"), kw(b="foo")) == (q, "hi there", "foo")] |
| 61 | + # in case of duplicate name across kws, rightmost wins |
| 62 | + test[(f, kw(a="hi there"), kw(b="foo"), kw(b="bar")) == (q, "hi there", "bar")] |
| 63 | + |
| 64 | + with testset("starargs"): |
| 65 | + # give *args with unpythonic.fun.apply, like in Lisps: |
| 66 | + lst = [1, 2, 3] |
| 67 | + def g(*args, **kwargs): |
| 68 | + return args + tuple(sorted(kwargs.items())) |
| 69 | + test[(apply, g, lst) == (q, 1, 2, 3)] |
| 70 | + # lst goes last; may have other args first |
| 71 | + test[(apply, g, "hi", "ho", lst) == (q, "hi", "ho", 1, 2, 3)] |
| 72 | + # named args in apply are also fine |
| 73 | + test[(apply, g, "hi", "ho", lst, kw(myarg=4)) == (q, "hi", "ho", 1, 2, 3, ('myarg', 4))] |
| 74 | + |
| 75 | + with testset("integration with let and do"): |
| 76 | + # prefix leaves alone the let binding syntax ((name0, value0), ...) |
| 77 | + a = let((x, 42))[x << x + 1] |
| 78 | + test[a == 43] |
| 79 | + |
| 80 | + # but the RHSs of the bindings are transformed normally: |
| 81 | + def double(x): |
| 82 | + return 2 * x |
| 83 | + a = let((x, (double, 21)))[x << x + 1] |
| 84 | + test[a == 43] |
| 85 | + |
| 86 | + # similarly, prefix leaves the "body tuple" of a do alone |
| 87 | + # (syntax, not semantically a tuple), but recurses into it: |
| 88 | + a = do[1, 2, 3] |
| 89 | + test[a == 3] |
| 90 | + a = do[1, 2, (double, 3)] |
| 91 | + test[a == 6] |
| 92 | + |
| 93 | + # the extra bracket syntax has no danger of confusion, as it's a list, not tuple |
| 94 | + a = let((x, 3))[[ |
| 95 | + 1, |
| 96 | + 2, |
| 97 | + (double, x)]] |
| 98 | + test[a == 6] |
| 99 | + |
| 100 | + # Introducing the LisThEll programming language: an all-in-one solution with |
| 101 | + # the prefix syntax of Lisp, the speed of Python, and the readability of Haskell! |
| 102 | + with testset("LisThEll"): |
| 103 | + with prefix, curry: |
| 104 | + mymap = lambda f: (foldr, (compose, cons, f), nil) |
| 105 | + double = lambda x: 2 * x |
| 106 | + (print, (mymap, double, (q, 1, 2, 3))) |
| 107 | + test[(mymap, double, (q, 1, 2, 3)) == ll(2, 4, 6)] |
102 | 108 |
|
103 | 109 | if __name__ == '__main__': |
104 | 110 | runtests() |
0 commit comments