cython-devel
changeset 2203:4495287d2fdb
NoneCheckNode to enforce runtime None checks for object references
| author | Stefan Behnel <scoder@users.berlios.de> |
|---|---|
| date | Sun Mar 29 20:55:51 2009 +0200 (2 years ago) |
| parents | 0afd7738bd5e |
| children | 91be9458f343 |
| files | Cython/Compiler/ExprNodes.py Cython/Compiler/Optimize.py |
line diff
1.1 --- a/Cython/Compiler/ExprNodes.py Sun Mar 29 20:44:11 2009 +0200
1.2 +++ b/Cython/Compiler/ExprNodes.py Sun Mar 29 20:55:51 2009 +0200
1.3 @@ -5091,7 +5091,44 @@
1.4
1.5 def free_temps(self, code):
1.6 self.arg.free_temps(code)
1.7 -
1.8 +
1.9 +
1.10 +class NoneCheckNode(CoercionNode):
1.11 + # This node is used to check that a Python object is not None and
1.12 + # raises an appropriate exception (as specified by the creating
1.13 + # transform).
1.14 +
1.15 + def __init__(self, arg, exception_type_cname, exception_message):
1.16 + CoercionNode.__init__(self, arg)
1.17 + self.type = arg.type
1.18 + self.result_ctype = arg.ctype()
1.19 + self.exception_type_cname = exception_type_cname
1.20 + self.exception_message = exception_message
1.21 +
1.22 + def analyse_types(self, env):
1.23 + pass
1.24 +
1.25 + def result_in_temp(self):
1.26 + return self.arg.result_in_temp()
1.27 +
1.28 + def calculate_result_code(self):
1.29 + return self.arg.result()
1.30 +
1.31 + def generate_result_code(self, code):
1.32 + code.putln(
1.33 + "if (unlikely(%s == Py_None)) {" % self.arg.result())
1.34 + code.putln('PyErr_SetString(%s, "%s"); %s ' % (
1.35 + self.exception_type_cname,
1.36 + StringEncoding.escape_byte_string(self.exception_message),
1.37 + code.error_goto(self.pos)))
1.38 + code.putln("}")
1.39 +
1.40 + def generate_post_assignment_code(self, code):
1.41 + self.arg.generate_post_assignment_code(code)
1.42 +
1.43 + def free_temps(self, code):
1.44 + self.arg.free_temps(code)
1.45 +
1.46
1.47 class CoerceToPyTypeNode(CoercionNode):
1.48 # This node is used to convert a C data type
2.1 --- a/Cython/Compiler/Optimize.py Sun Mar 29 20:44:11 2009 +0200
2.2 +++ b/Cython/Compiler/Optimize.py Sun Mar 29 20:55:51 2009 +0200
2.3 @@ -476,6 +476,7 @@
2.4 arg_list = arg_tuple.args
2.5 self_arg = function.obj
2.6 obj_type = self_arg.type
2.7 + is_unbound_method = False
2.8 if obj_type.is_builtin_type:
2.9 if obj_type is Builtin.type_type and arg_list and \
2.10 arg_list[0].type.is_pyobject:
2.11 @@ -483,6 +484,7 @@
2.12 # (ignoring 'type.mro()' here ...)
2.13 type_name = function.obj.name
2.14 self_arg = None
2.15 + is_unbound_method = True
2.16 else:
2.17 type_name = obj_type.name
2.18 else:
2.19 @@ -494,9 +496,9 @@
2.20 if self_arg is not None:
2.21 arg_list = [self_arg] + list(arg_list)
2.22 if kwargs:
2.23 - return method_handler(node, arg_list, kwargs)
2.24 + return method_handler(node, arg_list, kwargs, is_unbound_method)
2.25 else:
2.26 - return method_handler(node, arg_list)
2.27 + return method_handler(node, arg_list, is_unbound_method)
2.28 else:
2.29 return node
2.30
2.31 @@ -625,7 +627,7 @@
2.32 PyrexTypes.CFuncTypeArg("item", PyrexTypes.py_object_type, None),
2.33 ])
2.34
2.35 - def _handle_simple_method_object_append(self, node, args):
2.36 + def _handle_simple_method_object_append(self, node, args, is_unbound_method):
2.37 # X.append() is almost always referring to a list
2.38 if len(args) != 2:
2.39 return node
2.40 @@ -644,13 +646,14 @@
2.41 ],
2.42 exception_value = "-1")
2.43
2.44 - def _handle_simple_method_list_append(self, node, args):
2.45 + def _handle_simple_method_list_append(self, node, args, is_unbound_method):
2.46 if len(args) != 2:
2.47 error(node.pos, "list.append(x) called with wrong number of args, found %d" %
2.48 len(args))
2.49 return node
2.50 return self._substitute_method_call(
2.51 - node, "PyList_Append", self.PyList_Append_func_type, args)
2.52 + node, "PyList_Append", self.PyList_Append_func_type,
2.53 + 'append', is_unbound_method, args)
2.54
2.55 single_param_func_type = PyrexTypes.CFuncType(
2.56 PyrexTypes.c_int_type, [
2.57 @@ -658,21 +661,37 @@
2.58 ],
2.59 exception_value = "-1")
2.60
2.61 - def _handle_simple_method_list_sort(self, node, args):
2.62 + def _handle_simple_method_list_sort(self, node, args, is_unbound_method):
2.63 if len(args) != 1:
2.64 return node
2.65 return self._substitute_method_call(
2.66 - node, "PyList_Sort", self.single_param_func_type, args)
2.67 + node, "PyList_Sort", self.single_param_func_type,
2.68 + 'sort', is_unbound_method, args)
2.69
2.70 - def _handle_simple_method_list_reverse(self, node, args):
2.71 + def _handle_simple_method_list_reverse(self, node, args, is_unbound_method):
2.72 if len(args) != 1:
2.73 error(node.pos, "list.reverse(x) called with wrong number of args, found %d" %
2.74 len(args))
2.75 + return node
2.76 return self._substitute_method_call(
2.77 - node, "PyList_Reverse", self.single_param_func_type, args)
2.78 + node, "PyList_Reverse", self.single_param_func_type,
2.79 + 'reverse', is_unbound_method, args)
2.80
2.81 - def _substitute_method_call(self, node, name, func_type, args=()):
2.82 + def _substitute_method_call(self, node, name, func_type,
2.83 + attr_name, is_unbound_method, args=()):
2.84 args = list(args)
2.85 + if args:
2.86 + self_arg = args[0]
2.87 + if is_unbound_method:
2.88 + self_arg = ExprNodes.NoneCheckNode(
2.89 + self_arg, "PyExc_TypeError",
2.90 + "descriptor '%s' requires a '%s' object but received a 'NoneType'" % (
2.91 + attr_name, node.function.obj.name))
2.92 + else:
2.93 + self_arg = ExprNodes.NoneCheckNode(
2.94 + self_arg, "PyExc_AttributeError",
2.95 + "'NoneType' object has no attribute '%s'" % attr_name)
2.96 + args[0] = self_arg
2.97 # FIXME: args[0] may need a runtime None check (ticket #166)
2.98 return ExprNodes.PythonCapiCallNode(
2.99 node.pos, name, func_type,
