Commit b6f46a39 authored by Dag Sverre Seljebotn's avatar Dag Sverre Seljebotn

Changed name from "fork" to "insertion_point" (codewriter), introduced func context

parent ace9e7f1
...@@ -25,7 +25,7 @@ class AnnotationCCodeWriter(CCodeWriter): ...@@ -25,7 +25,7 @@ class AnnotationCCodeWriter(CCodeWriter):
self.last_pos = None self.last_pos = None
self.code = {} self.code = {}
else: 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.annotation_buffer = create_from.annotation_buffer
self.annotations = create_from.annotations self.annotations = create_from.annotations
self.code = create_from.code self.code = create_from.code
......
...@@ -11,27 +11,107 @@ from TypeSlots import method_coexist ...@@ -11,27 +11,107 @@ from TypeSlots import method_coexist
from Scanning import SourceDescriptor from Scanning import SourceDescriptor
from Cython.StringIOTree import StringIOTree 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): class CCodeWriter(object):
""" """
Utility class to output C code. Each codewriter is forkable (see Utility class to output C code.
StringIOTree).
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: kept:
- formatting state (level, bol) is cloned and modifyable in - formatting state (level, bol) is cloned and used in insertion points
all forked copies as well
- labels, temps, exc_vars: One must construct a scope in which these can - 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 exist by calling enter_cfunc_scope/exit_cfunc_scope (these are for
sanity checking and forward compatabilty). When a fork happens, only sanity checking and forward compatabilty). Created insertion points
the *last* fork will maintain this created scope, while the other looses this scope and cannot access it.
instances "looses" their ability to use temps and labels (as this - marker: Not copied to insertion point
is sufficient for current usecases). - filename_table, filename_list, input_file_contents: All codewriters
- utility code: Same story as with labels and temps; use enter_implementation coming from the same root share the same instances simultaneously.
and exit_implementation.
- marker: Only kept in last fork.
- filename_table, filename_list, input_file_contents: All forks share
the same instances simultaneously.
-
""" """
# f file output file # f file output file
...@@ -52,7 +132,8 @@ class CCodeWriter(object): ...@@ -52,7 +132,8 @@ class CCodeWriter(object):
# exc_vars (string * 3) exception variables for reraise, or None # 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 # input_file_contents dict contents (=list of lines) of any file that was used as input
# to create this output C code. This is # 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 in_try_finally = 0
...@@ -61,6 +142,7 @@ class CCodeWriter(object): ...@@ -61,6 +142,7 @@ class CCodeWriter(object):
self.buffer = buffer self.buffer = buffer
self.marker = None self.marker = None
self.last_marker_line = 0 self.last_marker_line = 0
self.func = None
if create_from is None: if create_from is None:
# Root CCodeWriter # Root CCodeWriter
self.level = 0 self.level = 0
...@@ -69,13 +151,11 @@ class CCodeWriter(object): ...@@ -69,13 +151,11 @@ class CCodeWriter(object):
self.filename_list = [] self.filename_list = []
self.exc_vars = None self.exc_vars = None
self.input_file_contents = {} self.input_file_contents = {}
self.in_cfunc = False
else: else:
# Clone formatting state # Clone formatting state
c = create_from c = create_from
self.level = c.level self.level = c.level
self.bol = c.bol self.bol = c.bol
self.in_cfunc = c.in_cfunc
# Note: NOT copying but sharing instance # Note: NOT copying but sharing instance
self.filename_table = c.filename_table self.filename_table = c.filename_table
self.filename_list = [] self.filename_list = []
...@@ -95,31 +175,39 @@ class CCodeWriter(object): ...@@ -95,31 +175,39 @@ class CCodeWriter(object):
def write(self, s): def write(self, s):
self.buffer.write(s) self.buffer.write(s)
def fork(self): def insertion_point(self):
other = self.create_new(create_from=self, buffer=self.buffer.fork()) other = self.create_new(create_from=self, buffer=self.buffer.insertion_point())
# If we need to do something with our own state on fork, do it here
return other 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): def enter_cfunc_scope(self):
assert not self.in_cfunc self.func = FunctionContext()
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
def exit_cfunc_scope(self): def exit_cfunc_scope(self):
self.in_cfunc = False self.func = None
del self.error_label
del self.label_counter
del self.labels_used
del self.return_label
del self.continue_label
del self.break_label
def putln(self, code = ""): def putln(self, code = ""):
if self.marker and self.bol: if self.marker and self.bol:
...@@ -199,68 +287,13 @@ class CCodeWriter(object): ...@@ -199,68 +287,13 @@ class CCodeWriter(object):
source_desc.get_escaped_description(), line, u'\n'.join(lines)) source_desc.get_escaped_description(), line, u'\n'.join(lines))
self.marker = (line, marker) 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): def put_label(self, lbl):
if lbl in self.labels_used: if lbl in self.func.labels_used:
self.putln("%s:;" % lbl) self.putln("%s:;" % lbl)
def put_goto(self, lbl): def put_goto(self, lbl):
self.use_label(lbl) self.func.use_label(lbl)
self.putln("goto %s;" % lbl) self.putln("goto %s;" % lbl)
def put_var_declarations(self, entries, static = 0, dll_linkage = None, def put_var_declarations(self, entries, static = 0, dll_linkage = None,
...@@ -412,8 +445,8 @@ class CCodeWriter(object): ...@@ -412,8 +445,8 @@ class CCodeWriter(object):
return cond return cond
def error_goto(self, pos): def error_goto(self, pos):
lbl = self.error_label lbl = self.func.error_label
self.use_label(lbl) self.func.use_label(lbl)
if Options.c_line_in_traceback: if Options.c_line_in_traceback:
cinfo = " %s = %s;" % (Naming.clineno_cname, Naming.line_c_macro) cinfo = " %s = %s;" % (Naming.clineno_cname, Naming.line_c_macro)
else: else:
......
...@@ -239,7 +239,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -239,7 +239,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code = Annotate.AnnotationCCodeWriter() code = Annotate.AnnotationCCodeWriter()
else: else:
code = Code.CCodeWriter() code = Code.CCodeWriter()
h_code = code.fork() h_code = code.insertion_point()
self.generate_module_preamble(env, modules, h_code) self.generate_module_preamble(env, modules, h_code)
code.putln("") code.putln("")
......
...@@ -24,7 +24,7 @@ class StringIOTree(object): ...@@ -24,7 +24,7 @@ class StringIOTree(object):
def write(self, what): def write(self, what):
self.stream.write(what) self.stream.write(what)
def fork(self): def insertion_point(self):
# Save what we have written until now # Save what we have written until now
# (would it be more efficient to check with len(self.stream.getvalue())? # (would it be more efficient to check with len(self.stream.getvalue())?
# leaving it out for now) # leaving it out for now)
...@@ -36,30 +36,29 @@ class StringIOTree(object): ...@@ -36,30 +36,29 @@ class StringIOTree(object):
return other return other
__doc__ = r""" __doc__ = r"""
Implements a forkable buffer. When you know you need to "get back" to a place Implements a buffer with insertion points. When you know you need to
and write more later, simply call fork() at that spot and get a new "get back" to a place and write more later, simply call insertion_point()
StringIOTree object that is "left behind", *behind* the object that is at that spot and get a new StringIOTree object that is "left behind".
forked.
EXAMPLE: EXAMPLE:
>>> pyrex = StringIOTree() >>> a = StringIOTree()
>>> pyrex.write('first\n') >>> a.write('first\n')
>>> cython = pyrex.fork() >>> b = a.insertion_point()
>>> pyrex.write('third\n') >>> a.write('third\n')
>>> cython.write('second\n') >>> b.write('second\n')
>>> print pyrex.getvalue() >>> print a.getvalue()
first first
second second
third third
<BLANKLINE> <BLANKLINE>
>>> b = cython.fork() >>> c = b.insertion_point()
>>> a = b.fork() >>> d = c.insertion_point()
>>> a.write('alpha\n') >>> d.write('alpha\n')
>>> cython.write('gamma\n') >>> b.write('gamma\n')
>>> b.write('beta\n') >>> c.write('beta\n')
>>> print cython.getvalue() >>> print b.getvalue()
second second
alpha alpha
beta beta
...@@ -67,7 +66,7 @@ gamma ...@@ -67,7 +66,7 @@ gamma
<BLANKLINE> <BLANKLINE>
>>> out = StringIO() >>> out = StringIO()
>>> pyrex.copyto(out) >>> a.copyto(out)
>>> print out.getvalue() >>> print out.getvalue()
first first
second second
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment