From 9534cbd1f8f46eed5e8f62829b601b00daee0a93 Mon Sep 17 00:00:00 2001 From: Robert Bradshaw Date: Tue, 7 Oct 2008 20:18:12 -0700 Subject: [PATCH] Coercion of dict to struct. --- Cython/Compiler/ExprNodes.py | 71 +++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 0b9f21cb..ff1494fb 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -2880,6 +2880,8 @@ class DictNode(ExprNode): # Dictionary constructor. # # key_value_pairs [DictItemNode] + # + # obj_conversion_errors [PyrexError] used internally subexprs = ['key_value_pairs'] @@ -2892,11 +2894,52 @@ class DictNode(ExprNode): self.compile_time_value_error(e) def analyse_types(self, env): + hold_errors() for item in self.key_value_pairs: item.analyse_types(env) - self.type = dict_type self.gil_check(env) + self.obj_conversion_errors = held_errors() + release_errors(ignore=True) + self.type = dict_type self.is_temp = 1 + + def coerce_to(self, dst_type, env): + if dst_type.is_pyobject: + self.release_errors() + if not self.type.subtype_of(dst_type): + error(self.pos, "Cannot interpret dict as type '%s'" % dst_type) + elif dst_type.is_struct_or_union: + self.type = dst_type + if not dst_type.is_struct and len(self.key_value_pairs) != 1: + error(self.pos, "Exactly one field must be specified to convert to union '%s'" % dst_type) + elif dst_type.is_struct and len(self.key_value_pairs) < len(dst_type.scope.var_entries): + warning(self.pos, "Not all members given for struct '%s'" % dst_type, 1) + for item in self.key_value_pairs: + if isinstance(item.key, CoerceToPyTypeNode): + item.key = item.key.arg + if isinstance(item.key, (StringNode, IdentifierStringNode)): + item.key = NameNode(pos=item.key.pos, name=item.key.value) + if not isinstance(item.key, NameNode): + print item.key + error(item.key.pos, "Struct field must be a name") + else: + member = dst_type.scope.lookup_here(item.key.name) + if not member: + error(item.key.pos, "struct '%s' has no field '%s'" % (dst_type, item.key.name)) + else: + value = item.value + if isinstance(value, CoerceToPyTypeNode): + value = value.arg + item.value = value.coerce_to(member.type, env) + else: + self.type = error_type + error(self.pos, "Cannot interpret dict as type '%s'" % dst_type) + return self + + def release_errors(self): + for err in self.obj_conversion_errors: + report_error(err) + self.obj_conversion_errors = [] gil_message = "Constructing Python dict" @@ -2913,17 +2956,25 @@ class DictNode(ExprNode): def generate_evaluation_code(self, code): # Custom method used here because key-value # pairs are evaluated and used one at a time. - code.putln( - "%s = PyDict_New(); %s" % ( - self.result(), - code.error_goto_if_null(self.result(), self.pos))) + if self.type.is_pyobject: + self.release_errors() + code.putln( + "%s = PyDict_New(); %s" % ( + self.result(), + code.error_goto_if_null(self.result(), self.pos))) for item in self.key_value_pairs: item.generate_evaluation_code(code) - code.put_error_if_neg(self.pos, - "PyDict_SetItem(%s, %s, %s)" % ( - self.result(), - item.key.py_result(), - item.value.py_result())) + if self.type.is_pyobject: + code.put_error_if_neg(self.pos, + "PyDict_SetItem(%s, %s, %s)" % ( + self.result(), + item.key.py_result(), + item.value.py_result())) + else: + code.putln("%s.%s = %s;" % ( + self.result(), + item.key.name, + item.value.result())) item.generate_disposal_code(code) def annotate(self, code): -- 2.26.2