From ef83d2ab14f8075c3096566350999cc9ecf79abc Mon Sep 17 00:00:00 2001 From: Robert Bradshaw Date: Wed, 8 Oct 2008 01:54:50 -0700 Subject: [PATCH] struct to object via dict --- Cython/Compiler/ExprNodes.py | 7 +++--- Cython/Compiler/Naming.py | 1 + Cython/Compiler/PyrexTypes.py | 43 ++++++++++++++++++++++++++++++++++- Cython/Compiler/Symtab.py | 11 ++++++++- 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 978d9ef6..f87d14f4 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -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): diff --git a/Cython/Compiler/Naming.py b/Cython/Compiler/Naming.py index 13d15c45..bfed035e 100644 --- a/Cython/Compiler/Naming.py +++ b/Cython/Compiler/Naming.py @@ -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" diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index 8e5c73ec..e22a7441 100644 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -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 "" % (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 "" diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index eca416a7..1547dc82 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -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, -- 2.26.2