# closure tests

# simple closure:
def make_adder(x):
    def g(y):
        return x + y
    return g

a = make_adder(1)
print a(5)
print map(a, range(5))

def make_adder2(x2):
    # f takes a closure since it needs to get a reference to x2 to pass to g
    def f():
        def g(y2):
            return x2 + y2
        return g

    r = f()
    print r(1)
    x2 += 1
    print r(1)
    return r

a = make_adder2(2)
print a(5)
print map(a, range(5))

def make_addr3(x3):
    # this function doesn't take a closure:
    def f1():
        return 2
    f1()

    def g(y3):
        return x3 + y3

    # this function does a different closure
    def f2():
        print f1()
    f2()
    return g
print make_addr3(10)(2)

def f4(args):
     def inner():
       for a in args:
         print a
     return inner
print f4([1, 2, 3])()

def f5():
    x = 12039
    def i1():
        def i2():
            print x
        i2()
    i1()
f5()

def f6():
    x = 131
    # Regression test:
    # default args shouldn't mess with closure analysis
    def inner(a=1):
        print x
    inner()

    print (lambda a=1: x)()
f6()


# Regression test: make sure we can handle two pass-through-closure frames in a row
def f7(n):
    class C(object):
        class D(object):
            def foo(self):
                return n

    return C.D

c = f7(5)()
print c.foo()


# Regression test: being included in a closure (ie in the parent scope) shouldn't ruin type analysis.
def f8():
    l = []

    def g():
        print l

    l.append(1)
for i in xrange(11000):
    f8()
