Commit 774b88c6 authored by Robert Bradshaw's avatar Robert Bradshaw

Merge pull request #200 from nnemkin/module_level_literal_arrays

Allow module-level literal lists (Fixes #113).
parents 16cb9327 71d13da9
......@@ -484,7 +484,7 @@ class FunctionState(object):
self.in_try_finally = 0
self.exc_vars = None
self.temps_allocated = [] # of (name, type, manage_ref)
self.temps_allocated = [] # of (name, type, manage_ref, static)
self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status
self.temps_used_type = {} # name -> (type, manage_ref)
self.temp_counter = 0
......@@ -563,7 +563,7 @@ class FunctionState(object):
# temp handling
def allocate_temp(self, type, manage_ref):
def allocate_temp(self, type, manage_ref, static=False):
"""
Allocates a temporary (which may create a new one or get a previously
allocated and released one of the same type). Type is simply registered
......@@ -578,6 +578,10 @@ class FunctionState(object):
still has to be passed. It is recommended to pass False by convention
if it is known that type will never be a Python object.
static=True marks the temporary declaration with "static".
This is only used when allocating backing store for a module-level
C array literals.
A C string referring to the variable is returned.
"""
if type.is_const:
......@@ -595,7 +599,7 @@ class FunctionState(object):
self.temp_counter += 1
result = "%s%d" % (Naming.codewriter_temp_prefix, self.temp_counter)
if not result in self.names_taken: break
self.temps_allocated.append((result, type, manage_ref))
self.temps_allocated.append((result, type, manage_ref, static))
self.temps_used_type[result] = (type, manage_ref)
if DebugFlags.debug_temp_code_comments:
self.owner.putln("/* %s allocated */" % result)
......@@ -626,7 +630,7 @@ class FunctionState(object):
that are currently in use.
"""
used = []
for name, type, manage_ref in self.temps_allocated:
for name, type, manage_ref, static in self.temps_allocated:
freelist = self.temps_free.get((type, manage_ref))
if freelist is None or name not in freelist:
used.append((name, type, manage_ref and type.is_pyobject))
......@@ -645,7 +649,7 @@ class FunctionState(object):
"""Return a list of (cname, type) tuples of refcount-managed Python objects.
"""
return [(cname, type)
for cname, type, manage_ref in self.temps_allocated
for cname, type, manage_ref, static in self.temps_allocated
if manage_ref]
def all_free_managed_temps(self):
......@@ -1604,7 +1608,7 @@ class CCodeWriter(object):
self.putln(";")
def put_temp_declarations(self, func_context):
for name, type, manage_ref in func_context.temps_allocated:
for name, type, manage_ref, static in func_context.temps_allocated:
decl = type.declaration_code(name)
if type.is_pyobject:
self.putln("%s = NULL;" % decl)
......@@ -1612,7 +1616,7 @@ class CCodeWriter(object):
import MemoryView
self.putln("%s = %s;" % (decl, MemoryView.memslice_entry_init))
else:
self.putln("%s;" % decl)
self.putln("%s%s;" % (static and "static " or "", decl))
def put_h_guard(self, guard):
self.putln("#ifndef %s" % guard)
......
......@@ -1815,7 +1815,7 @@ class NameNode(AtomicExprNode):
return # There was an error earlier
if (self.entry.type.is_ptr and isinstance(rhs, ListNode)
and not self.lhs_of_first_assignment):
and not self.lhs_of_first_assignment and not rhs.in_module_scope):
error(self.pos, "Literal list must be assigned to pointer at time of declaration")
# is_pyglobal seems to be True for module level-globals only.
......@@ -5914,6 +5914,7 @@ class ListNode(SequenceNode):
obj_conversion_errors = []
type = list_type
in_module_scope = False
gil_message = "Constructing Python list"
......@@ -5934,6 +5935,8 @@ class ListNode(SequenceNode):
node = SequenceNode.analyse_types(self, env)
node.obj_conversion_errors = held_errors()
release_errors(ignore=True)
if env.is_module_scope:
self.in_module_scope = True
return node
def coerce_to(self, dst_type, env):
......@@ -5975,6 +5978,13 @@ class ListNode(SequenceNode):
t.constant_result = tuple(self.constant_result)
return t
def allocate_temp_result(self, code):
if self.type.is_array and self.in_module_scope:
self.temp_code = code.funcstate.allocate_temp(
self.type, manage_ref=False, static=True)
else:
SequenceNode.allocate_temp_result(self, code)
def release_temp_result(self, env):
if self.type.is_array:
# To be valid C++, we must allocate the memory on the stack
......
......@@ -55,6 +55,26 @@ def test_struct(int x, y):
print_struct(aa[0])
print_struct([1, 2, <double**>1])
cdef int m_int = -1
cdef int* m_iarray = [4, m_int]
cdef int** m_piarray = [m_iarray, &m_int]
cdef char** m_carray = [b"a", b"bc"]
cdef MyStruct* m_structarray = [[m_int,0,NULL], [1,m_int+1,NULL]]
def test_module_level():
"""
>>> test_module_level()
4 -1
4 -1
True True
1 0 True
"""
print m_iarray[0], m_iarray[1]
print m_piarray[0][0], m_piarray[1][0]
print m_carray[0] == b"a", m_carray[1] == b"bc"
print_struct(m_structarray[1])
# Make sure it's still naturally an object.
[0,1,2,3].append(4)
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