1# mode: run
2# tag: closures
3# ticket: 82
4# preparse: id
5# preparse: def_to_cdef
6
7cimport cython
8
9def add_n(int n):
10    """
11    >>> f = add_n(3)
12    >>> f(2)
13    5
14
15    >>> f = add_n(1000000)
16    >>> f(1000000), f(-1000000)
17    (2000000, 0)
18    """
19    def f(int x):
20        return x+n
21    return f
22
23def a(int x):
24    """
25    >>> a(5)()
26    8
27    """
28    def b():
29        def c():
30            return 3+x
31        return c()
32    return b
33
34def local_x(int arg_x):
35    """
36    >>> local_x(1)(2)(4)
37    4 2 1
38    15
39    """
40    cdef int local_x = arg_x
41    def y(arg_y):
42        y = arg_y
43        def z(long arg_z):
44            cdef long z = arg_z
45            print z, y, local_x
46            return 8+z+y+local_x
47        return z
48    return y
49
50def x(int x):
51    """
52    >>> x(1)(2)(4)
53    15
54    """
55    def y(y):
56        def z(long z):
57            return 8+z+y+x
58        return z
59    return y
60
61def x2(int x2):
62    """
63    >>> x2(1)(2)(4)
64    4 2 1
65    15
66    """
67    def y2(y2):
68        def z2(long z2):
69            print z2, y2, x2
70            return 8+z2+y2+x2
71        return z2
72    return y2
73
74
75def inner_override(a,b):
76    """
77    >>> inner_override(2,4)()
78    5
79    """
80    def f():
81        a = 1
82        return a+b
83    return f
84
85
86def reassign(x):
87    """
88    >>> reassign(4)(2)
89    3
90    """
91    def f(a):
92        return a+x
93    x = 1
94    return f
95
96def reassign_int(x):
97    """
98    >>> reassign_int(4)(2)
99    3
100    """
101    def f(int a):
102        return a+x
103    x = 1
104    return f
105
106def reassign_int_int(int x):
107    """
108    >>> reassign_int_int(4)(2)
109    3
110    """
111    def f(int a):
112        return a+x
113    x = 1
114    return f
115
116
117def cy_twofuncs(x):
118    """
119    >>> def py_twofuncs(x):
120    ...    def f(a):
121    ...        return g(x) + a
122    ...    def g(b):
123    ...        return x + b
124    ...    return f
125
126    >>> py_twofuncs(1)(2) == cy_twofuncs(1)(2)
127    True
128    >>> py_twofuncs(3)(5) == cy_twofuncs(3)(5)
129    True
130    """
131    def f(a):
132        return g(x) + a
133    def g(b):
134        return x + b
135    return f
136
137def switch_funcs(a, b, int ix):
138    """
139    >>> switch_funcs([1,2,3], [4,5,6], 0)([10])
140    [1, 2, 3, 10]
141    >>> switch_funcs([1,2,3], [4,5,6], 1)([10])
142    [4, 5, 6, 10]
143    >>> switch_funcs([1,2,3], [4,5,6], 2) is None
144    True
145    """
146    def f(x):
147        return a + x
148    def g(x):
149        return b + x
150    if ix == 0:
151        return f
152    elif ix == 1:
153        return g
154    else:
155        return None
156
157def ignore_func(x):
158    def f():
159        return x
160    return None
161
162def call_ignore_func():
163    """
164    >>> call_ignore_func()
165    """
166    ignore_func((1,2,3))
167
168def more_inner_funcs(x):
169    """
170    >>> inner_funcs = more_inner_funcs(1)(2,4,8)
171    >>> inner_funcs[0](16), inner_funcs[1](32), inner_funcs[2](64)
172    (19, 37, 73)
173    """
174    # called with x==1
175    def f(a):
176        def g(b):
177            # called with 16
178            return a+b+x
179        return g
180    def g(b):
181        def f(a):
182            # called with 32
183            return a+b+x
184        return f
185    def h(b):
186        def f(a):
187            # called with 64
188            return a+b+x
189        return f
190    def resolve(a_f, b_g, b_h):
191        # called with (2,4,8)
192        return f(a_f), g(b_g), h(b_h)
193    return resolve
194
195
196@cython.test_assert_path_exists("//DefNode//DefNode//DefNode//DefNode",
197                                "//DefNode[@needs_outer_scope = False]", # deep_inner()
198                                "//DefNode//DefNode//DefNode//DefNode[@needs_closure = False]", # h()
199                                )
200@cython.test_fail_if_path_exists("//DefNode//DefNode[@needs_outer_scope = False]")
201def deep_inner():
202    """
203    >>> deep_inner()()
204    2
205    """
206    cdef int x = 1
207    def f():
208        def g():
209            def h():
210                return x+1
211            return h
212        return g()
213    return f()
214
215
216@cython.test_assert_path_exists("//DefNode//DefNode//DefNode",
217                                "//DefNode//DefNode//DefNode[@needs_outer_scope = False]",  # a()
218                                "//DefNode//DefNode//DefNode[@needs_closure = False]", # a(), g(), h()
219                                )
220@cython.test_fail_if_path_exists("//DefNode//DefNode//DefNode[@needs_closure = True]") # a(), g(), h()
221def deep_inner_sibling():
222    """
223    >>> deep_inner_sibling()()
224    2
225    """
226    cdef int x = 1
227    def f():
228        def a():
229            return 1
230        def g():
231            return x+a()
232        def h():
233            return g()
234        return h
235    return f()
236