From: Dag Sverre Seljebotn Date: Wed, 30 Jul 2008 08:54:59 +0000 (+0200) Subject: Changed name from "fork" to "insertion_point" (codewriter), introduced func context X-Git-Tag: 0.9.8.1~49^2~49 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=b6f46a392b7d902fc96a348c427a6166714aaba5;p=cython.git Changed name from "fork" to "insertion_point" (codewriter), introduced func context --- diff --git a/Cython/Compiler/Annotate.py b/Cython/Compiler/Annotate.py index 7e2d8c70..6336b142 100644 --- a/Cython/Compiler/Annotate.py +++ b/Cython/Compiler/Annotate.py @@ -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 diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index f837dda8..bc7ef507 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -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: diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 6e4b20dd..f2662a7e 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -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("") diff --git a/Cython/StringIOTree.py b/Cython/StringIOTree.py index 45cf6619..5f4fb879 100644 --- a/Cython/StringIOTree.py +++ b/Cython/StringIOTree.py @@ -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 ->>> 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 >>> out = StringIO() ->>> pyrex.copyto(out) +>>> a.copyto(out) >>> print out.getvalue() first second