From: Nikita Nemkin Date: Thu, 28 Mar 2013 11:11:10 +0000 (+0600) Subject: Allow module-level literal lists (Fixes #113). X-Git-Tag: 0.19b1~19^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=71d13da97ec0961c133a0d36e5a6466368fba393;p=platform%2Fupstream%2Fpython-cython.git Allow module-level literal lists (Fixes #113). --- diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index 94b1246..807e6e0 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -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) diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index ec4d52b..afffb1d 100755 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -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 diff --git a/tests/run/literal_lists.pyx b/tests/run/literal_lists.pyx index 35fd74f..57942ef 100644 --- a/tests/run/literal_lists.pyx +++ b/tests/run/literal_lists.pyx @@ -55,6 +55,26 @@ def test_struct(int x, y): print_struct(aa[0]) print_struct([1, 2, 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)