Add 1994 Coroutine module by Tim Peters
diff --git a/Demo/threads/Coroutine.py b/Demo/threads/Coroutine.py
new file mode 100644
index 0000000..0cf9255
--- /dev/null
+++ b/Demo/threads/Coroutine.py
@@ -0,0 +1,160 @@
+# Coroutine implementation using Python threads.
+#
+# Combines ideas from Guido's Generator module, and from the coroutine
+# features of Icon and Simula 67.
+#
+# To run a collection of functions as coroutines, you need to create
+# a Coroutine object to control them:
+#    co = Coroutine()
+# and then 'create' a subsidiary object for each function in the
+# collection:
+#    cof1 = co.create(f1 [, arg1, arg2, ...]) # [] means optional,
+#    cof2 = co.create(f2 [, arg1, arg2, ...]) #... not list
+#    cof3 = co.create(f3 [, arg1, arg2, ...])
+# etc.  The functions need not be distinct; 'create'ing the same
+# function multiple times gives you independent instances of the
+# function.
+#
+# To start the coroutines running, use co.tran on one of the create'd
+# functions; e.g., co.tran(cof2).  The routine that first executes
+# co.tran is called the "main coroutine".  It's special in several
+# respects:  it existed before you created the Coroutine object; if any of
+# the create'd coroutines exits (does a return, or suffers an unhandled
+# exception), EarlyExit error is raised in the main coroutine; and the
+# co.detach() method transfers control directly to the main coroutine
+# (you can't use co.tran() for this because the main coroutine doesn't
+# have a name ...).
+#
+# Coroutine objects support these methods:
+#
+# handle = .create(func [, arg1, arg2, ...])
+#    Creates a coroutine for an invocation of func(arg1, arg2, ...),
+#    and returns a handle ("name") for the coroutine so created.  The
+#    handle can be used as the target in a subsequent .tran().
+#
+# .tran(target, data=None)
+#    Transfer control to the create'd coroutine "target", optionally
+#    passing it an arbitrary piece of data. To the coroutine A that does
+#    the .tran, .tran acts like an ordinary function call:  another
+#    coroutine B can .tran back to it later, and if it does A's .tran
+#    returns the 'data' argument passed to B's tran.  E.g.,
+#
+#    in coroutine coA   in coroutine coC    in coroutine coB
+#      x = co.tran(coC)   co.tran(coB)        co.tran(coA,12)
+#      print x # 12
+#
+#    The data-passing feature is taken from Icon, and greatly cuts
+#    the need to use global variables for inter-coroutine communication.
+#
+# .back( data=None )
+#    The same as .tran(invoker, data=None), where 'invoker' is the
+#    coroutine that most recently .tran'ed control to the coroutine
+#    doing the .back.  This is akin to Icon's "&source".
+#
+# .detach( data=None )
+#    The same as .tran(main, data=None), where 'main' is the
+#    (unnameable!) coroutine that started it all.  'main' has all the
+#    rights of any other coroutine:  upon receiving control, it can
+#    .tran to an arbitrary coroutine of its choosing, go .back to
+#    the .detach'er, or .kill the whole thing.
+#
+# .kill()
+#    Destroy all the coroutines, and return control to the main
+#    coroutine.  None of the create'ed coroutines can be resumed after a
+#    .kill().  An EarlyExit exception does a .kill() automatically.  It's
+#    a good idea to .kill() coroutines you're done with, since the
+#    current implementation consumes a thread for each coroutine that
+#    may be resumed.
+
+import thread
+import sync
+
+class _CoEvent:
+    def __init__(self, func):
+        self.f = func
+        self.e = sync.event()
+
+    def __repr__(self):
+        if self.f is None:
+            return 'main coroutine'
+        else:
+            return 'coroutine for func ' + self.f.func_name
+
+    def __hash__(self):
+        return id(self)
+
+    def __cmp__(x,y):
+        return cmp(id(x), id(y))
+
+    def resume(self):
+        self.e.post()
+
+    def wait(self):
+        self.e.wait()
+        self.e.clear()
+
+Killed = 'Coroutine.Killed'
+EarlyExit = 'Coroutine.EarlyExit'
+
+class Coroutine:
+    def __init__(self):
+        self.active = self.main = _CoEvent(None)
+        self.invokedby = {self.main: None}
+        self.killed = 0
+        self.value  = None
+        self.terminated_by = None
+
+    def create(self, func, *args):
+        me = _CoEvent(func)
+        self.invokedby[me] = None
+        thread.start_new_thread(self._start, (me,) + args)
+        return me
+
+    def _start(self, me, *args):
+        me.wait()
+        if not self.killed:
+            try:
+                try:
+                    apply(me.f, args)
+                except Killed:
+                    pass
+            finally:
+                if not self.killed:
+                    self.terminated_by = me
+                    self.kill()
+
+    def kill(self):
+        if self.killed:
+            raise TypeError, 'kill() called on dead coroutines'
+        self.killed = 1
+        for coroutine in self.invokedby.keys():
+            coroutine.resume()
+
+    def back(self, data=None):
+        return self.tran( self.invokedby[self.active], data )
+
+    def detach(self, data=None):
+        return self.tran( self.main, data )
+
+    def tran(self, target, data=None):
+        if not self.invokedby.has_key(target):
+            raise TypeError, '.tran target ' + `target` + \
+                             ' is not an active coroutine'
+        if self.killed:
+            raise TypeError, '.tran target ' + `target` + ' is killed'
+        self.value = data
+        me = self.active
+        self.invokedby[target] = me
+        self.active = target
+        target.resume()
+
+        me.wait()
+        if self.killed:
+            if self.main is not me:
+                raise Killed
+            if self.terminated_by is not None:
+                raise EarlyExit, `self.terminated_by` + ' terminated early'
+
+        return self.value
+
+# end of module
diff --git a/Demo/threads/README b/Demo/threads/README
index c6c4a0b..fe27818 100644
--- a/Demo/threads/README
+++ b/Demo/threads/README
@@ -8,3 +8,7 @@
 sync.py		Condition variables primitives by Tim Peters.
 telnet.py	Version of ../sockets/telnet.py using threads.
 wpi.py		Version of ../scripts/pi.py using threads (needs stdwin).
+
+Coroutine.py	Coroutines using threads, by Tim Peters (22 May 94)
+fcmp.py		Example of above, by Tim
+squasher.py	Another example of above, also by Tim
diff --git a/Demo/threads/fcmp.py b/Demo/threads/fcmp.py
new file mode 100644
index 0000000..37a2087
--- /dev/null
+++ b/Demo/threads/fcmp.py
@@ -0,0 +1,64 @@
+# Coroutine example:  controlling multiple instances of a single function
+
+from Coroutine import *
+
+# fringe visits a nested list in inorder, and detaches for each non-list
+# element; raises EarlyExit after the list is exhausted
+def fringe( co, list ):
+    for x in list:
+        if type(x) is type([]):
+            fringe(co, x)
+        else:
+            co.detach(x)
+
+def printinorder( list ):
+    co = Coroutine()
+    f = co.create(fringe, co, list)
+    try:
+        while 1:
+            print co.tran(f),
+    except EarlyExit:
+        pass
+    print
+
+printinorder([1,2,3])  # 1 2 3
+printinorder([[[[1,[2]]],3]]) # ditto
+x = [0, 1, [2, [3]], [4,5], [[[6]]] ]
+printinorder(x) # 0 1 2 3 4 5 6
+
+# fcmp lexicographically compares the fringes of two nested lists
+def fcmp( l1, l2 ):
+    co1 = Coroutine(); f1 = co1.create(fringe, co1, l1)
+    co2 = Coroutine(); f2 = co2.create(fringe, co2, l2)
+    while 1:
+        try:
+            v1 = co1.tran(f1)
+        except EarlyExit:
+            try:
+                v2 = co2.tran(f2)
+            except EarlyExit:
+                return 0
+            co2.kill()
+            return -1
+        try:
+            v2 = co2.tran(f2)
+        except EarlyExit:
+            co1.kill()
+            return 1
+        if v1 != v2:
+            co1.kill(); co2.kill()
+            return cmp(v1,v2)
+
+print fcmp(range(7), x)  #  0; fringes are equal
+print fcmp(range(6), x)  # -1; 1st list ends early
+print fcmp(x, range(6))  #  1; 2nd list ends early
+print fcmp(range(8), x)  #  1; 2nd list ends early
+print fcmp(x, range(8))  # -1; 1st list ends early
+print fcmp([1,[[2],8]],
+           [[[1],2],8])  #  0
+print fcmp([1,[[3],8]],
+           [[[1],2],8])  #  1
+print fcmp([1,[[2],8]],
+           [[[1],2],9])  # -1
+
+# end of example
diff --git a/Demo/threads/squasher.py b/Demo/threads/squasher.py
new file mode 100644
index 0000000..3d5ea00
--- /dev/null
+++ b/Demo/threads/squasher.py
@@ -0,0 +1,104 @@
+# Coroutine example:  general coroutine transfers
+#
+# The program is a variation of a Simula 67 program due to Dahl & Hoare,
+# who in turn credit the original example to Conway.
+#
+# We have a number of input lines, terminated by a 0 byte.  The problem
+# is to squash them together into output lines containing 72 characters
+# each.  A semicolon must be added between input lines.  Runs of blanks
+# and tabs in input lines must be squashed into single blanks.
+# Occurrences of "**" in input lines must be replaced by "^".
+#
+# Here's a test case:
+
+test = """\
+   d    =   sqrt(b**2  -  4*a*c)
+twoa    =   2*a
+   L    =   -b/twoa
+   R    =   d/twoa
+  A1    =   L + R
+  A2    =   L - R\0
+"""
+
+# The program should print:
+
+# d = sqrt(b^2 - 4*a*c);twoa = 2*a; L = -b/twoa; R = d/twoa; A1 = L + R;
+#A2 = L - R
+#done
+
+# getline: delivers the next input line to its invoker
+# disassembler: grabs input lines from getline, and delivers them one
+#    character at a time to squasher, also inserting a semicolon into
+#    the stream between lines
+# squasher:  grabs characters from disassembler and passes them on to
+#    assembler, first replacing "**" with "^" and squashing runs of
+#    whitespace
+# assembler: grabs characters from squasher and packs them into lines
+#    with 72 character each, delivering each such line to putline;
+#    when it sees a null byte, passes the last line to putline and
+#    then kills all the coroutines
+# putline: grabs lines from assembler, and just prints them
+
+from Coroutine import *
+
+def getline(text):
+    for line in string.splitfields(text, '\n'):
+        co.back(line)
+
+def disassembler():
+    while 1:
+        card = co.tran(cogetline)
+        for i in range(len(card)):
+            co.tran(cosquasher, card[i])
+        co.tran(cosquasher, ';')
+
+def squasher():
+    while 1:
+        ch = co.tran(codisassembler)
+        if ch == '*':
+            ch2 = co.tran(codisassembler)
+            if ch2 == '*':
+                ch = '^'
+            else:
+                co.tran(coassembler, ch)
+                ch = ch2
+        if ch in ' \t':
+            while 1:
+                ch2 = co.tran(codisassembler)
+                if ch2 not in ' \t':
+                    break
+            co.tran(coassembler, ' ')
+            ch = ch2
+        co.tran(coassembler, ch)
+
+def assembler():
+    line = ''
+    while 1:
+        ch = co.tran(cosquasher)
+        if ch == '\0':
+            break
+        if len(line) == 72:
+            co.tran(coputline, line)
+            line = ''
+        line = line + ch
+    line = line + ' ' * (72 - len(line))
+    co.tran(coputline, line)
+    co.kill()
+
+def putline():
+    while 1:
+        line = co.tran(coassembler)
+        print line
+
+import string
+co = Coroutine()
+cogetline = co.create(getline, test)
+coputline = co.create(putline)
+coassembler = co.create(assembler)
+codisassembler = co.create(disassembler)
+cosquasher = co.create(squasher)
+
+co.tran(coputline)
+print 'done'
+
+# end of example