struct to object via dict
authorRobert Bradshaw <robertwb@math.washington.edu>
Wed, 8 Oct 2008 08:54:50 +0000 (01:54 -0700)
committerRobert Bradshaw <robertwb@math.washington.edu>
Wed, 8 Oct 2008 08:54:50 +0000 (01:54 -0700)
Cython/Compiler/ExprNodes.py
Cython/Compiler/Naming.py
Cython/Compiler/PyrexTypes.py
Cython/Compiler/Symtab.py

index 978d9ef68e253923fba5e39ee238adb8c0ff90de..f87d14f4805bf9c12219726ba96348bf4b5f1442 100644 (file)
@@ -3351,7 +3351,8 @@ class TypecastNode(ExprNode):
         if from_py and not to_py and self.operand.is_ephemeral() and not self.type.is_numeric:
             error(self.pos, "Casting temporary Python object to non-numeric non-Python type")
         if to_py and not from_py:
-            if self.operand.type.to_py_function:
+            if (self.operand.type.to_py_function and
+                    self.operand.type.create_convert_utility_code(env)):
                 self.result_ctype = py_object_type
                 self.operand = self.operand.coerce_to_pyobject(env)
             else:
@@ -4388,10 +4389,10 @@ class CoerceToPyTypeNode(CoercionNode):
         self.type = py_object_type
         self.gil_check(env)
         self.is_temp = 1
-        if not arg.type.to_py_function:
+        if not arg.type.to_py_function or not arg.type.create_convert_utility_code(env):
             error(arg.pos,
                 "Cannot convert '%s' to Python object" % arg.type)
-
+        
     gil_message = "Converting to Python object"
 
     def analyse_types(self, env):
index 13d15c455eb5fbf9e0de1ee9605138c7a62c1d43..bfed035e0d224687d934ca4ba6dbd3cfbfcb9627 100644 (file)
@@ -42,6 +42,7 @@ vtable_prefix     = pyrex_prefix + "vtable_"
 vtabptr_prefix    = pyrex_prefix + "vtabptr_"
 vtabstruct_prefix = pyrex_prefix + "vtabstruct_"
 opt_arg_prefix    = pyrex_prefix + "opt_args_"
+convert_func_prefix = pyrex_prefix + "convert_"
 
 args_cname       = pyrex_prefix + "args"
 pykwdlist_cname  = pyrex_prefix + "pyargnames"
index 8e5c73ec3c29c36fde534840eb1b330a2c889445..e22a7441d193a9669490af91cd6a3c371fc48d0a 100644 (file)
@@ -404,7 +404,10 @@ class CType(PyrexType):
     from_py_function = None
     exception_value = None
     exception_check = 1
-    
+
+    def create_convert_utility_code(self, env):
+        return True
+        
     def error_condition(self, result_code):
         conds = []
         if self.is_string:
@@ -932,6 +935,41 @@ class CStructOrUnionType(CType):
         self.scope = scope
         self.typedef_flag = typedef_flag
         self.is_struct = kind == 'struct'
+        if self.is_struct:
+            self.to_py_function = "%s_to_py_%s" % (Naming.convert_func_prefix, self.cname)
+        self.exception_check = True
+        self._convert_code = None
+        
+    def create_convert_utility_code(self, env):
+        if env.outer_scope is None:
+            return False
+        if self._convert_code is None:
+            import Code
+            code = Code.CCodeWriter()
+            header = "static PyObject* %s(%s)" % (self.to_py_function, self.declaration_code('s'))
+            code.putln("%s {" % header)
+            code.putln("PyObject* res;")
+            code.putln("PyObject* member;")
+            code.putln("res = PyDict_New(); if (res == NULL) return NULL;")
+            for member in self.scope.var_entries:
+                if member.type.to_py_function and member.type.create_convert_utility_code(env):
+                    code.putln("member = %s(s.%s); if (member == NULL) goto bad;" % (
+                                                member.type.to_py_function, member.cname))
+                    code.putln("if (PyDict_SetItem(res, %s, member) < 0) goto bad;" % member.py_name.pystring_cname)
+                    code.putln("Py_DECREF(member);")
+                else:
+                    self.to_py_function = None
+                    return False
+            code.putln("return res;")
+            code.putln("bad:")
+            code.putln("Py_XDECREF(member);")
+            code.putln("Py_DECREF(res);")
+            code.putln("return NULL;")
+            code.putln("}")
+            self._convert_code = self.declaration_code('') + ';\n' + header+";", code.buffer.getvalue()
+        
+        env.use_utility_code(self._convert_code)
+        return True
         
     def __repr__(self):
         return "<CStructOrUnionType %s %s%s>" % (self.name, self.cname,
@@ -1076,6 +1114,9 @@ class ErrorType(PyrexType):
     from_py_function = "dummy"
     typestring = None
     
+    def create_convert_utility_code(self, env):
+        return True
+    
     def declaration_code(self, entity_code, 
             for_display = 0, dll_linkage = None, pyrex = 0):
         return "<error>"
index eca416a76c37f9bb8076c8c23f55e4e481b7e5ae..1547dc82917170c9e8679fe18f6064f5b6c6c15f 100644 (file)
@@ -359,6 +359,8 @@ class Scope:
                     self.type_entries.append(entry)
         if not scope and not entry.type.scope:
             self.check_for_illegal_incomplete_ctypedef(typedef_flag, pos)
+        if scope and self.outer_scope:
+            scope.module_scope = self
         return entry
     
     def check_previous_typedef_flag(self, entry, typedef_flag, pos):
@@ -959,7 +961,8 @@ class ModuleScope(Scope):
         return "%s%s%d" % (Naming.const_prefix, prefix, n)
     
     def use_utility_code(self, new_code, name=None):
-        self.utility_code_list.append((new_code, name))
+        if new_code is not None:
+            self.utility_code_list.append((new_code, name))
 
     def declare_c_class(self, name, pos, defining = 0, implementing = 0,
         module_name = None, base_type = None, objstruct_cname = None,
@@ -1203,6 +1206,8 @@ class GeneratorLocalScope(LocalScope):
 
 class StructOrUnionScope(Scope):
     #  Namespace of a C struct or union.
+    
+    module_scope = None
 
     def __init__(self, name="?"):
         Scope.__init__(self, name, None, None)
@@ -1216,6 +1221,10 @@ class StructOrUnionScope(Scope):
             type = PyrexTypes.CPtrType(type)
         entry = self.declare(name, cname, type, pos, visibility)
         entry.is_variable = 1
+        if self.module_scope:
+            py_name = self.module_scope.get_string_const(name, identifier=True)
+            self.module_scope.add_py_string(py_name)
+            entry.py_name = py_name
         self.var_entries.append(entry)
         if type.is_pyobject and not allow_pyobject:
             error(pos,