# An attempt to emulate scope guard statements of the D Programming Language
# see: http://d...content-available-to-author-only...s.com/2.0/statement.html#ScopeGuardStatement

def noop(*args, **kwargs):
    pass

def mkCbAdder(typ):
    def adder(self, cb):
        self.callbacks.append( (typ, cb) )
    return adder

class Scope(object):

    def __init__(self):
        self.callbacks = []

    exit = property(noop, mkCbAdder('exit'))
    success = property(noop, mkCbAdder('ok'))
    failure = property(noop, mkCbAdder('fail'))

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        ok = value is None
        while self.callbacks:
            typ, cb = self.callbacks.pop()
            if typ is 'exit':
                cb()
            elif ok and typ is 'ok':
                cb()
            elif not ok and (typ is 'fail'):
                cb()


def write(arg):
    return lambda: print(arg, end="")


write(1)()
with Scope() as s:
    write(2)()
    s.exit = write(3)
    s.exit = write(4)
    write(5)()

# 12543

print()

with Scope() as s:
    s.exit = write(1)
    s.success = write(2)
    s.exit = write(3)
    s.success = write(4)

# 4321

print()

try:
    with Scope() as s:
        s.exit = write(1)
        s.success = write(2)
        s.failure = write(3)
        raise Exception("msg")
        s.exit = write(4)
        s.success = write(5)
        s.failure = write(6)
        
except Exception as e:
    pass

# 31
