Changed name from "fork" to "insertion_point" (codewriter), introduced func context
authorDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Wed, 30 Jul 2008 08:54:59 +0000 (10:54 +0200)
committerDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Wed, 30 Jul 2008 08:54:59 +0000 (10:54 +0200)
Cython/Compiler/Annotate.py
Cython/Compiler/Code.py
Cython/Compiler/ModuleNode.py
Cython/StringIOTree.py

index 7e2d8c70e0f6c55bfdcfaea115f1e8a47dfbda80..6336b1420ca816ad62cebfcd29ecd33a49efc49f 100644 (file)
@@ -25,7 +25,7 @@ class AnnotationCCodeWriter(CCodeWriter):
             self.last_pos = None
             self.code = {}
         else:
-            # When forking, keep references to the same database
+            # When creating an insertion point, keep references to the same database
             self.annotation_buffer = create_from.annotation_buffer
             self.annotations = create_from.annotations
             self.code = create_from.code
index f837dda827eb466f164e3bf5689884877dd104d6..bc7ef507ee9e278592383420ea339e03a0192b01 100644 (file)
@@ -11,27 +11,107 @@ from TypeSlots import method_coexist
 from Scanning import SourceDescriptor
 from Cython.StringIOTree import StringIOTree
 
+class FunctionContext(object):
+    # Not used for now, perhaps later
+    def __init__(self):
+        self.error_label = None
+        self.label_counter = 0
+        self.labels_used = {}
+        self.return_label = self.new_label()
+        self.new_error_label()
+        self.continue_label = None
+        self.break_label = None
+
+        self.temps_allocated = []
+        self.temps_free = {} # type -> list of free vars 
+
+    def new_label(self):
+        n = self.label_counter
+        self.label_counter = n + 1
+        return "%s%d" % (Naming.label_prefix, n)
+    
+    def new_error_label(self):
+        old_err_lbl = self.error_label
+        self.error_label = self.new_label()
+        return old_err_lbl
+    
+    def get_loop_labels(self):
+        return (
+            self.continue_label,
+            self.break_label)
+    
+    def set_loop_labels(self, labels):
+        (self.continue_label,
+         self.break_label) = labels
+    
+    def new_loop_labels(self):
+        old_labels = self.get_loop_labels()
+        self.set_loop_labels(
+            (self.new_label(), 
+             self.new_label()))
+        return old_labels
+    
+    def get_all_labels(self):
+        return (
+            self.continue_label,
+            self.break_label,
+            self.return_label,
+            self.error_label)
+
+    def set_all_labels(self, labels):
+        (self.continue_label,
+         self.break_label,
+         self.return_label,
+         self.error_label) = labels
+
+    def all_new_labels(self):
+        old_labels = self.get_all_labels()
+        new_labels = []
+        for old_label in old_labels:
+            if old_label:
+                new_labels.append(self.new_label())
+            else:
+                new_labels.append(old_label)
+        self.set_all_labels(new_labels)
+        return old_labels
+    
+    def use_label(self, lbl):
+        self.labels_used[lbl] = 1
+        
+    def label_used(self, lbl):
+        return lbl in self.labels_used
+
+    def allocate_temp(self, type):
+        freelist = self.temps_free.get(type)
+        if freelist is not None and len(freelist) > 0:
+            return freelist.pop()
+        else:
+            pass
+
+
+
+def funccontext_property(name):
+    def get(self):
+        return getattr(self.func, name)
+    def set(self, value):
+        setattr(self.func, name, value)
+    return property(get, set)
+
 class CCodeWriter(object):
     """
-    Utility class to output C code. Each codewriter is forkable (see
-    StringIOTree).
+    Utility class to output C code.
 
-    When forking a code writer one must care about the state that is
+    When creating an insertion point one must care about the state that is
     kept:
-    - formatting state (level, bol) is cloned and modifyable in
-      all forked copies
+    - formatting state (level, bol) is cloned and used in insertion points
+      as well
     - labels, temps, exc_vars: One must construct a scope in which these can
       exist by calling enter_cfunc_scope/exit_cfunc_scope (these are for
-      sanity checking and forward compatabilty). When a fork happens, only
-      the *last* fork will maintain this created scope, while the other
-      instances "looses" their ability to use temps and labels (as this
-      is sufficient for current usecases).
-    - utility code: Same story as with labels and temps; use enter_implementation
-      and exit_implementation.
-    - marker: Only kept in last fork.
-    - filename_table, filename_list, input_file_contents: All forks share
-      the same instances simultaneously.
-    - 
+      sanity checking and forward compatabilty). Created insertion points
+      looses this scope and cannot access it.
+    - marker: Not copied to insertion point
+    - filename_table, filename_list, input_file_contents: All codewriters
+      coming from the same root share the same instances simultaneously.
     """ 
     
     # f                file            output file
@@ -52,7 +132,8 @@ class CCodeWriter(object):
     # exc_vars         (string * 3)    exception variables for reraise, or None
     # input_file_contents dict         contents (=list of lines) of any file that was used as input
     #                                  to create this output C code.  This is
-    #                                  used to annotate the comments. 
+    #                                  used to annotate the comments.
+    # func             FunctionContext contains labels and temps context info
    
     in_try_finally = 0
     
@@ -61,6 +142,7 @@ class CCodeWriter(object):
         self.buffer = buffer
         self.marker = None
         self.last_marker_line = 0
+        self.func = None
         if create_from is None:
             # Root CCodeWriter
             self.level = 0
@@ -69,13 +151,11 @@ class CCodeWriter(object):
             self.filename_list = []
             self.exc_vars = None
             self.input_file_contents = {}
-            self.in_cfunc = False
         else:
             # Clone formatting state
             c = create_from
             self.level = c.level
             self.bol = c.bol
-            self.in_cfunc = c.in_cfunc
             # Note: NOT copying but sharing instance
             self.filename_table = c.filename_table
             self.filename_list = []
@@ -95,31 +175,39 @@ class CCodeWriter(object):
 
     def write(self, s):
         self.buffer.write(s)
-        
-    def fork(self):
-        other = self.create_new(create_from=self, buffer=self.buffer.fork())
-        # If we need to do something with our own state on fork, do it here
+
+    def insertion_point(self):
+        other = self.create_new(create_from=self, buffer=self.buffer.insertion_point())
         return other
 
+
+    # Properties delegated to function scope
+    label_counter = funccontext_property("label_counter")
+    return_label = funccontext_property("return_label")
+    error_label = funccontext_property("error_label")
+    labels_used = funccontext_property("labels_used")
+    continue_label = funccontext_property("continue_label")
+    break_label = funccontext_property("break_label")
+
+
+    # Functions delegated to function scope
+    def new_label(self):               return self.func.new_label()
+    def new_error_label(self):         return self.func.new_error_label()
+    def get_loop_labels(self):         return self.func.get_loop_labels()
+    def set_loop_labels(self, labels): return self.func.set_loop_labels(labels)
+    def new_loop_labels(self):         return self.func.new_loop_labels()
+    def get_all_labels(self):          return self.func.get_all_labels()
+    def set_all_labels(self, labels):  return self.func.set_all_labels(labels)
+    def all_new_labels(self):          return self.func.all_new_labels()
+    def use_label(self, lbl):          return self.func.use_label(lbl)
+    def label_used(self, lbl):         return self.func.label_used(lbl)
+
+
     def enter_cfunc_scope(self):
-        assert not self.in_cfunc
-        self.in_cfunc = True
-        self.error_label = None
-        self.label_counter = 0
-        self.labels_used = {}
-        self.return_label = self.new_label()
-        self.new_error_label()
-        self.continue_label = None
-        self.break_label = None
+        self.func = FunctionContext()
     
     def exit_cfunc_scope(self):
-        self.in_cfunc = False
-        del self.error_label
-        del self.label_counter
-        del self.labels_used
-        del self.return_label
-        del self.continue_label
-        del self.break_label
+        self.func = None
 
     def putln(self, code = ""):
         if self.marker and self.bol:
@@ -199,68 +287,13 @@ class CCodeWriter(object):
             source_desc.get_escaped_description(), line, u'\n'.join(lines))
         self.marker = (line, marker)
 
-    def new_label(self):
-        n = self.label_counter
-        self.label_counter = n + 1
-        return "%s%d" % (Naming.label_prefix, n)
-    
-    def new_error_label(self):
-        old_err_lbl = self.error_label
-        self.error_label = self.new_label()
-        return old_err_lbl
-    
-    def get_loop_labels(self):
-        return (
-            self.continue_label,
-            self.break_label)
-    
-    def set_loop_labels(self, labels):
-        (self.continue_label,
-         self.break_label) = labels
-    
-    def new_loop_labels(self):
-        old_labels = self.get_loop_labels()
-        self.set_loop_labels(
-            (self.new_label(), 
-             self.new_label()))
-        return old_labels
-    
-    def get_all_labels(self):
-        return (
-            self.continue_label,
-            self.break_label,
-            self.return_label,
-            self.error_label)
-
-    def set_all_labels(self, labels):
-        (self.continue_label,
-         self.break_label,
-         self.return_label,
-         self.error_label) = labels
-
-    def all_new_labels(self):
-        old_labels = self.get_all_labels()
-        new_labels = []
-        for old_label in old_labels:
-            if old_label:
-                new_labels.append(self.new_label())
-            else:
-                new_labels.append(old_label)
-        self.set_all_labels(new_labels)
-        return old_labels
-    
-    def use_label(self, lbl):
-        self.labels_used[lbl] = 1
-        
-    def label_used(self, lbl):
-        return lbl in self.labels_used
         
     def put_label(self, lbl):
-        if lbl in self.labels_used:
+        if lbl in self.func.labels_used:
             self.putln("%s:;" % lbl)
     
     def put_goto(self, lbl):
-        self.use_label(lbl)
+        self.func.use_label(lbl)
         self.putln("goto %s;" % lbl)
     
     def put_var_declarations(self, entries, static = 0, dll_linkage = None,
@@ -412,8 +445,8 @@ class CCodeWriter(object):
             return cond
         
     def error_goto(self, pos):
-        lbl = self.error_label
-        self.use_label(lbl)
+        lbl = self.func.error_label
+        self.func.use_label(lbl)
         if Options.c_line_in_traceback:
             cinfo = " %s = %s;" % (Naming.clineno_cname, Naming.line_c_macro)
         else:
index 6e4b20dddb0a2a3db348a9a8c06de60873bc62a3..f2662a7ef88ddb84920f56887f27f1a558abc142 100644 (file)
@@ -239,7 +239,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             code = Annotate.AnnotationCCodeWriter()
         else:
             code = Code.CCodeWriter()
-        h_code = code.fork()
+        h_code = code.insertion_point()
         self.generate_module_preamble(env, modules, h_code)
 
         code.putln("")
index 45cf6619ae9a5216f0aa9e53427c160026bb5970..5f4fb8794e176f69cf83855265b2a4e876b935b4 100644 (file)
@@ -24,7 +24,7 @@ class StringIOTree(object):
     def write(self, what):
         self.stream.write(what)
 
-    def fork(self):
+    def insertion_point(self):
         # Save what we have written until now
         # (would it be more efficient to check with len(self.stream.getvalue())?
         # leaving it out for now)
@@ -36,30 +36,29 @@ class StringIOTree(object):
         return other
 
 __doc__ = r"""
-Implements a forkable buffer. When you know you need to "get back" to a place
-and write more later, simply call fork() at that spot and get a new
-StringIOTree object that is "left behind", *behind* the object that is
-forked.
+Implements a buffer with insertion points. When you know you need to
+"get back" to a place and write more later, simply call insertion_point()
+at that spot and get a new StringIOTree object that is "left behind".
 
 EXAMPLE:
 
->>> pyrex = StringIOTree()
->>> pyrex.write('first\n')
->>> cython = pyrex.fork()
->>> pyrex.write('third\n')
->>> cython.write('second\n')
->>> print pyrex.getvalue()
+>>> a = StringIOTree()
+>>> a.write('first\n')
+>>> b = a.insertion_point()
+>>> a.write('third\n')
+>>> b.write('second\n')
+>>> print a.getvalue()
 first
 second
 third
 <BLANKLINE>
 
->>> b = cython.fork()
->>> a = b.fork()
->>> a.write('alpha\n')
->>> cython.write('gamma\n')
->>> b.write('beta\n')
->>> print cython.getvalue()
+>>> c = b.insertion_point()
+>>> d = c.insertion_point()
+>>> d.write('alpha\n')
+>>> b.write('gamma\n')
+>>> c.write('beta\n')
+>>> print b.getvalue()
 second
 alpha
 beta
@@ -67,7 +66,7 @@ gamma
 <BLANKLINE>
 
 >>> out = StringIO()
->>> pyrex.copyto(out)
+>>> a.copyto(out)
 >>> print out.getvalue()
 first
 second