12 from Code import UtilityCode
13 from StringEncoding import EncodedString, BytesLiteral
14 from Errors import error
15 from ParseTreeTransforms import SkipDeclarations
22 from functools import reduce
27 from sets import Set as set
29 class FakePythonEnv(object):
30 "A fake environment for creating type test nodes etc."
33 def unwrap_coerced_node(node, coercion_nodes=(ExprNodes.CoerceToPyTypeNode, ExprNodes.CoerceFromPyTypeNode)):
34 if isinstance(node, coercion_nodes):
38 def unwrap_node(node):
39 while isinstance(node, UtilNodes.ResultRefNode):
40 node = node.expression
43 def is_common_value(a, b):
46 if isinstance(a, ExprNodes.NameNode) and isinstance(b, ExprNodes.NameNode):
47 return a.name == b.name
48 if isinstance(a, ExprNodes.AttributeNode) and isinstance(b, ExprNodes.AttributeNode):
49 return not a.is_py_attr and is_common_value(a.obj, b.obj) and a.attribute == b.attribute
52 class IterationTransform(Visitor.VisitorTransform):
53 """Transform some common for-in loop patterns into efficient C loops:
55 - for-in-dict loop becomes a while loop calling PyDict_Next()
56 - for-in-enumerate is replaced by an external counter variable
57 - for-in-range loop becomes a plain C for loop
59 PyDict_Next_func_type = PyrexTypes.CFuncType(
60 PyrexTypes.c_bint_type, [
61 PyrexTypes.CFuncTypeArg("dict", PyrexTypes.py_object_type, None),
62 PyrexTypes.CFuncTypeArg("pos", PyrexTypes.c_py_ssize_t_ptr_type, None),
63 PyrexTypes.CFuncTypeArg("key", PyrexTypes.CPtrType(PyrexTypes.py_object_type), None),
64 PyrexTypes.CFuncTypeArg("value", PyrexTypes.CPtrType(PyrexTypes.py_object_type), None)
67 PyDict_Next_name = EncodedString("PyDict_Next")
69 PyDict_Next_entry = Symtab.Entry(
70 PyDict_Next_name, PyDict_Next_name, PyDict_Next_func_type)
72 visit_Node = Visitor.VisitorTransform.recurse_to_children
74 def visit_ModuleNode(self, node):
75 self.current_scope = node.scope
76 self.visitchildren(node)
79 def visit_DefNode(self, node):
80 oldscope = self.current_scope
81 self.current_scope = node.entry.scope
82 self.visitchildren(node)
83 self.current_scope = oldscope
86 def visit_ForInStatNode(self, node):
87 self.visitchildren(node)
88 return self._optimise_for_loop(node)
90 def _optimise_for_loop(self, node):
91 iterator = node.iterator.sequence
92 if iterator.type is Builtin.dict_type:
93 # like iterating over dict.keys()
94 return self._transform_dict_iteration(
95 node, dict_obj=iterator, keys=True, values=False)
97 # C array (slice) iteration?
98 plain_iterator = unwrap_coerced_node(iterator)
99 if isinstance(plain_iterator, ExprNodes.SliceIndexNode) and \
100 (plain_iterator.base.type.is_array or plain_iterator.base.type.is_ptr):
101 return self._transform_carray_iteration(node, plain_iterator)
102 if isinstance(plain_iterator, ExprNodes.IndexNode) and \
103 isinstance(plain_iterator.index, (ExprNodes.SliceNode, ExprNodes.CoerceFromPyTypeNode)):
104 iterator_base = unwrap_coerced_node(plain_iterator.base)
105 if iterator_base.type.is_array or iterator_base.type.is_ptr:
106 return self._transform_carray_iteration(node, plain_iterator)
107 if iterator.type.is_array:
108 return self._transform_carray_iteration(node, iterator)
109 if iterator.type in (Builtin.bytes_type, Builtin.unicode_type):
110 return self._transform_string_iteration(node, iterator)
112 # the rest is based on function calls
113 if not isinstance(iterator, ExprNodes.SimpleCallNode):
116 function = iterator.function
118 if isinstance(function, ExprNodes.AttributeNode) and \
119 function.obj.type == Builtin.dict_type:
120 dict_obj = function.obj
121 method = function.attribute
123 keys = values = False
124 if method == 'iterkeys':
126 elif method == 'itervalues':
128 elif method == 'iteritems':
132 return self._transform_dict_iteration(
133 node, dict_obj, keys, values)
136 if iterator.self is None and function.is_name and \
137 function.entry and function.entry.is_builtin and \
138 function.name == 'enumerate':
139 return self._transform_enumerate_iteration(node, iterator)
142 if Options.convert_range and node.target.type.is_int:
143 if iterator.self is None and function.is_name and \
144 function.entry and function.entry.is_builtin and \
145 function.name in ('range', 'xrange'):
146 return self._transform_range_iteration(node, iterator)
150 PyUnicode_AS_UNICODE_func_type = PyrexTypes.CFuncType(
151 PyrexTypes.c_py_unicode_ptr_type, [
152 PyrexTypes.CFuncTypeArg("s", Builtin.unicode_type, None)
155 PyUnicode_GET_SIZE_func_type = PyrexTypes.CFuncType(
156 PyrexTypes.c_py_ssize_t_type, [
157 PyrexTypes.CFuncTypeArg("s", Builtin.unicode_type, None)
160 PyBytes_AS_STRING_func_type = PyrexTypes.CFuncType(
161 PyrexTypes.c_char_ptr_type, [
162 PyrexTypes.CFuncTypeArg("s", Builtin.bytes_type, None)
165 PyBytes_GET_SIZE_func_type = PyrexTypes.CFuncType(
166 PyrexTypes.c_py_ssize_t_type, [
167 PyrexTypes.CFuncTypeArg("s", Builtin.bytes_type, None)
170 def _transform_string_iteration(self, node, slice_node):
171 if not node.target.type.is_int:
173 if slice_node.type is Builtin.unicode_type:
174 unpack_func = "PyUnicode_AS_UNICODE"
175 len_func = "PyUnicode_GET_SIZE"
176 unpack_func_type = self.PyUnicode_AS_UNICODE_func_type
177 len_func_type = self.PyUnicode_GET_SIZE_func_type
178 elif slice_node.type is Builtin.bytes_type:
179 unpack_func = "PyBytes_AS_STRING"
180 unpack_func_type = self.PyBytes_AS_STRING_func_type
181 len_func = "PyBytes_GET_SIZE"
182 len_func_type = self.PyBytes_GET_SIZE_func_type
186 unpack_temp_node = UtilNodes.LetRefNode(
187 slice_node.as_none_safe_node("'NoneType' is not iterable"))
189 slice_base_node = ExprNodes.PythonCapiCallNode(
190 slice_node.pos, unpack_func, unpack_func_type,
191 args = [unpack_temp_node],
194 len_node = ExprNodes.PythonCapiCallNode(
195 slice_node.pos, len_func, len_func_type,
196 args = [unpack_temp_node],
200 return UtilNodes.LetNode(
202 self._transform_carray_iteration(
204 ExprNodes.SliceIndexNode(
206 base = slice_base_node,
210 type = slice_base_node.type,
214 def _transform_carray_iteration(self, node, slice_node):
216 if isinstance(slice_node, ExprNodes.SliceIndexNode):
217 slice_base = slice_node.base
218 start = slice_node.start
219 stop = slice_node.stop
223 elif isinstance(slice_node, ExprNodes.IndexNode):
224 # slice_node.index must be a SliceNode
225 slice_base = unwrap_coerced_node(slice_node.base)
226 index = unwrap_coerced_node(slice_node.index)
231 if step.constant_result is None:
233 elif not isinstance(step.constant_result, (int,long)) \
234 or step.constant_result == 0 \
235 or step.constant_result > 0 and not stop \
236 or step.constant_result < 0 and not start:
237 error(step.pos, "C array iteration requires known step size and end index")
240 # step sign is handled internally by ForFromStatNode
241 neg_step = step.constant_result < 0
242 step = ExprNodes.IntNode(step.pos, type=PyrexTypes.c_py_ssize_t_type,
243 value=abs(step.constant_result),
244 constant_result=abs(step.constant_result))
245 elif slice_node.type.is_array and slice_node.type.size is not None:
246 slice_base = slice_node
248 stop = ExprNodes.IntNode(
249 slice_node.pos, value=str(slice_node.type.size),
250 type=PyrexTypes.c_py_ssize_t_type, constant_result=slice_node.type.size)
256 if start.constant_result is None:
259 start = start.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_scope)
261 if stop.constant_result is None:
264 stop = stop.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_scope)
267 stop = ExprNodes.IntNode(
268 slice_node.pos, value='-1', type=PyrexTypes.c_py_ssize_t_type, constant_result=-1)
270 error(slice_node.pos, "C array iteration requires known step size and end index")
273 ptr_type = slice_base.type
274 if ptr_type.is_array:
275 ptr_type = ptr_type.element_ptr_type()
276 carray_ptr = slice_base.coerce_to_simple(self.current_scope)
278 if start and start.constant_result != 0:
279 start_ptr_node = ExprNodes.AddNode(
286 start_ptr_node = carray_ptr
288 stop_ptr_node = ExprNodes.AddNode(
290 operand1=ExprNodes.CloneNode(carray_ptr),
294 ).coerce_to_simple(self.current_scope)
296 counter = UtilNodes.TempHandle(ptr_type)
297 counter_temp = counter.ref(node.target.pos)
299 if slice_base.type.is_string and node.target.type.is_pyobject:
300 # special case: char* -> bytes
301 target_value = ExprNodes.SliceIndexNode(
303 start=ExprNodes.IntNode(node.target.pos, value='0',
305 type=PyrexTypes.c_int_type),
306 stop=ExprNodes.IntNode(node.target.pos, value='1',
308 type=PyrexTypes.c_int_type),
310 type=Builtin.bytes_type,
313 target_value = ExprNodes.IndexNode(
315 index=ExprNodes.IntNode(node.target.pos, value='0',
317 type=PyrexTypes.c_int_type),
319 is_buffer_access=False,
320 type=ptr_type.base_type)
322 if target_value.type != node.target.type:
323 target_value = target_value.coerce_to(node.target.type,
326 target_assign = Nodes.SingleAssignmentNode(
327 pos = node.target.pos,
331 body = Nodes.StatListNode(
333 stats = [target_assign, node.body])
335 for_node = Nodes.ForFromStatNode(
337 bound1=start_ptr_node, relation1=neg_step and '>=' or '<=',
339 relation2=neg_step and '>' or '<', bound2=stop_ptr_node,
340 step=step, body=body,
341 else_clause=node.else_clause,
344 return UtilNodes.TempsBlockNode(
345 node.pos, temps=[counter],
348 def _transform_enumerate_iteration(self, node, enumerate_function):
349 args = enumerate_function.arg_tuple.args
351 error(enumerate_function.pos,
352 "enumerate() requires an iterable argument")
355 error(enumerate_function.pos,
356 "enumerate() takes at most 1 argument")
359 if not node.target.is_sequence_constructor:
360 # leave this untouched for now
362 targets = node.target.args
363 if len(targets) != 2:
364 # leave this untouched for now
366 if not isinstance(targets[0], ExprNodes.NameNode):
367 # leave this untouched for now
370 enumerate_target, iterable_target = targets
371 counter_type = enumerate_target.type
373 if not counter_type.is_pyobject and not counter_type.is_int:
374 # nothing we can do here, I guess
377 temp = UtilNodes.LetRefNode(ExprNodes.IntNode(enumerate_function.pos,
381 inc_expression = ExprNodes.AddNode(
382 enumerate_function.pos,
384 operand2 = ExprNodes.IntNode(node.pos, value='1',
389 is_temp = counter_type.is_pyobject
393 Nodes.SingleAssignmentNode(
394 pos = enumerate_target.pos,
395 lhs = enumerate_target,
397 Nodes.SingleAssignmentNode(
398 pos = enumerate_target.pos,
400 rhs = inc_expression)
403 if isinstance(node.body, Nodes.StatListNode):
404 node.body.stats = loop_body + node.body.stats
406 loop_body.append(node.body)
407 node.body = Nodes.StatListNode(
411 node.target = iterable_target
412 node.item = node.item.coerce_to(iterable_target.type, self.current_scope)
413 node.iterator.sequence = enumerate_function.arg_tuple.args[0]
415 # recurse into loop to check for further optimisations
416 return UtilNodes.LetNode(temp, self._optimise_for_loop(node))
418 def _transform_range_iteration(self, node, range_function):
419 args = range_function.arg_tuple.args
421 step_pos = range_function.pos
423 step = ExprNodes.IntNode(step_pos, value='1',
428 if not isinstance(step.constant_result, (int, long)):
429 # cannot determine step direction
431 step_value = step.constant_result
433 # will lead to an error elsewhere
435 if not isinstance(step, ExprNodes.IntNode):
436 step = ExprNodes.IntNode(step_pos, value=str(step_value),
437 constant_result=step_value)
440 step.value = str(-step_value)
448 bound1 = ExprNodes.IntNode(range_function.pos, value='0',
450 bound2 = args[0].coerce_to_integer(self.current_scope)
452 bound1 = args[0].coerce_to_integer(self.current_scope)
453 bound2 = args[1].coerce_to_integer(self.current_scope)
454 step = step.coerce_to_integer(self.current_scope)
456 if not bound2.is_literal:
457 # stop bound must be immutable => keep it in a temp var
458 bound2_is_temp = True
459 bound2 = UtilNodes.LetRefNode(bound2)
461 bound2_is_temp = False
463 for_node = Nodes.ForFromStatNode(
466 bound1=bound1, relation1=relation1,
467 relation2=relation2, bound2=bound2,
468 step=step, body=node.body,
469 else_clause=node.else_clause,
473 for_node = UtilNodes.LetNode(bound2, for_node)
477 def _transform_dict_iteration(self, node, dict_obj, keys, values):
478 py_object_ptr = PyrexTypes.c_void_ptr_type
481 temp = UtilNodes.TempHandle(PyrexTypes.py_object_type)
483 dict_temp = temp.ref(dict_obj.pos)
484 temp = UtilNodes.TempHandle(PyrexTypes.c_py_ssize_t_type)
486 pos_temp = temp.ref(node.pos)
487 pos_temp_addr = ExprNodes.AmpersandNode(
488 node.pos, operand=pos_temp,
489 type=PyrexTypes.c_ptr_type(PyrexTypes.c_py_ssize_t_type))
491 temp = UtilNodes.TempHandle(py_object_ptr)
493 key_temp = temp.ref(node.target.pos)
494 key_temp_addr = ExprNodes.AmpersandNode(
495 node.target.pos, operand=key_temp,
496 type=PyrexTypes.c_ptr_type(py_object_ptr))
498 key_temp_addr = key_temp = ExprNodes.NullNode(
501 temp = UtilNodes.TempHandle(py_object_ptr)
503 value_temp = temp.ref(node.target.pos)
504 value_temp_addr = ExprNodes.AmpersandNode(
505 node.target.pos, operand=value_temp,
506 type=PyrexTypes.c_ptr_type(py_object_ptr))
508 value_temp_addr = value_temp = ExprNodes.NullNode(
511 key_target = value_target = node.target
514 if node.target.is_sequence_constructor:
515 if len(node.target.args) == 2:
516 key_target, value_target = node.target.args
518 # unusual case that may or may not lead to an error
521 tuple_target = node.target
523 def coerce_object_to(obj_node, dest_type):
524 if dest_type.is_pyobject:
525 if dest_type != obj_node.type:
526 if dest_type.is_extension_type or dest_type.is_builtin_type:
527 obj_node = ExprNodes.PyTypeTestNode(
528 obj_node, dest_type, self.current_scope, notnone=True)
529 result = ExprNodes.TypecastNode(
533 return (result, None)
535 temp = UtilNodes.TempHandle(dest_type)
537 temp_result = temp.ref(obj_node.pos)
538 class CoercedTempNode(ExprNodes.CoerceFromPyTypeNode):
540 return temp_result.result()
541 def generate_execution_code(self, code):
542 self.generate_result_code(code)
543 return (temp_result, CoercedTempNode(dest_type, obj_node, self.current_scope))
545 if isinstance(node.body, Nodes.StatListNode):
548 body = Nodes.StatListNode(pos = node.body.pos,
552 tuple_result = ExprNodes.TupleNode(
553 pos = tuple_target.pos,
554 args = [key_temp, value_temp],
556 type = Builtin.tuple_type,
559 0, Nodes.SingleAssignmentNode(
560 pos = tuple_target.pos,
564 # execute all coercions before the assignments
568 temp_result, coercion = coerce_object_to(
569 key_temp, key_target.type)
571 coercion_stats.append(coercion)
573 Nodes.SingleAssignmentNode(
578 temp_result, coercion = coerce_object_to(
579 value_temp, value_target.type)
581 coercion_stats.append(coercion)
583 Nodes.SingleAssignmentNode(
584 pos = value_temp.pos,
587 body.stats[0:0] = coercion_stats + assign_stats
590 Nodes.SingleAssignmentNode(
594 Nodes.SingleAssignmentNode(
597 rhs = ExprNodes.IntNode(node.pos, value='0',
601 condition = ExprNodes.SimpleCallNode(
603 type = PyrexTypes.c_bint_type,
604 function = ExprNodes.NameNode(
606 name = self.PyDict_Next_name,
607 type = self.PyDict_Next_func_type,
608 entry = self.PyDict_Next_entry),
609 args = [dict_temp, pos_temp_addr,
610 key_temp_addr, value_temp_addr]
613 else_clause = node.else_clause
617 return UtilNodes.TempsBlockNode(
618 node.pos, temps=temps,
619 body=Nodes.StatListNode(
625 class SwitchTransform(Visitor.VisitorTransform):
627 This transformation tries to turn long if statements into C switch statements.
628 The requirement is that every clause be an (or of) var == value, where the var
629 is common among all clauses and both var and value are ints.
631 NO_MATCH = (None, None, None)
633 def extract_conditions(self, cond, allow_not_in):
635 if isinstance(cond, ExprNodes.CoerceToTempNode):
637 elif isinstance(cond, UtilNodes.EvalWithTempExprNode):
638 # this is what we get from the FlattenInListTransform
639 cond = cond.subexpression
640 elif isinstance(cond, ExprNodes.TypecastNode):
645 if isinstance(cond, ExprNodes.PrimaryCmpNode):
646 if cond.cascade is None and not cond.is_python_comparison():
647 if cond.operator == '==':
649 elif allow_not_in and cond.operator == '!=':
651 elif cond.is_c_string_contains() and \
652 isinstance(cond.operand2, (ExprNodes.UnicodeNode, ExprNodes.BytesNode)):
653 not_in = cond.operator == 'not_in'
654 if not_in and not allow_not_in:
656 if isinstance(cond.operand2, ExprNodes.UnicodeNode) and \
657 cond.operand2.contains_surrogates():
658 # dealing with surrogates leads to different
659 # behaviour on wide and narrow Unicode
660 # platforms => refuse to optimise this case
662 # this looks somewhat silly, but it does the right
663 # checks for NameNode and AttributeNode
664 if is_common_value(cond.operand1, cond.operand1):
665 return not_in, cond.operand1, self.extract_in_string_conditions(cond.operand2)
670 # this looks somewhat silly, but it does the right
671 # checks for NameNode and AttributeNode
672 if is_common_value(cond.operand1, cond.operand1):
673 if cond.operand2.is_literal:
674 return not_in, cond.operand1, [cond.operand2]
675 elif getattr(cond.operand2, 'entry', None) \
676 and cond.operand2.entry.is_const:
677 return not_in, cond.operand1, [cond.operand2]
678 if is_common_value(cond.operand2, cond.operand2):
679 if cond.operand1.is_literal:
680 return not_in, cond.operand2, [cond.operand1]
681 elif getattr(cond.operand1, 'entry', None) \
682 and cond.operand1.entry.is_const:
683 return not_in, cond.operand2, [cond.operand1]
684 elif isinstance(cond, ExprNodes.BoolBinopNode):
685 if cond.operator == 'or' or (allow_not_in and cond.operator == 'and'):
686 allow_not_in = (cond.operator == 'and')
687 not_in_1, t1, c1 = self.extract_conditions(cond.operand1, allow_not_in)
688 not_in_2, t2, c2 = self.extract_conditions(cond.operand2, allow_not_in)
689 if t1 is not None and not_in_1 == not_in_2 and is_common_value(t1, t2):
690 if (not not_in_1) or allow_not_in:
691 return not_in_1, t1, c1+c2
694 def extract_in_string_conditions(self, string_literal):
695 if isinstance(string_literal, ExprNodes.UnicodeNode):
696 charvals = map(ord, set(string_literal.value))
698 return [ ExprNodes.IntNode(string_literal.pos, value=str(charval),
699 constant_result=charval)
700 for charval in charvals ]
702 # this is a bit tricky as Py3's bytes type returns
703 # integers on iteration, whereas Py2 returns 1-char byte
705 characters = string_literal.value
706 characters = list(set([ characters[i:i+1] for i in range(len(characters)) ]))
708 return [ ExprNodes.CharNode(string_literal.pos, value=charval,
709 constant_result=charval)
710 for charval in characters ]
712 def extract_common_conditions(self, common_var, condition, allow_not_in):
713 not_in, var, conditions = self.extract_conditions(condition, allow_not_in)
716 elif common_var is not None and not is_common_value(var, common_var):
718 elif not var.type.is_int or sum([not cond.type.is_int for cond in conditions]):
720 return not_in, var, conditions
722 def has_duplicate_values(self, condition_values):
723 # duplicated values don't work in a switch statement
725 for value in condition_values:
726 if value.constant_result is not ExprNodes.not_a_constant:
727 if value.constant_result in seen:
729 seen.add(value.constant_result)
731 # this isn't completely safe as we don't know the
732 # final C value, but this is about the best we can do
733 seen.add(getattr(getattr(value, 'entry', None), 'cname'))
736 def visit_IfStatNode(self, node):
739 for if_clause in node.if_clauses:
740 _, common_var, conditions = self.extract_common_conditions(
741 common_var, if_clause.condition, False)
742 if common_var is None:
743 self.visitchildren(node)
745 cases.append(Nodes.SwitchCaseNode(pos = if_clause.pos,
746 conditions = conditions,
747 body = if_clause.body))
749 if sum([ len(case.conditions) for case in cases ]) < 2:
750 self.visitchildren(node)
752 if self.has_duplicate_values(sum([case.conditions for case in cases], [])):
753 self.visitchildren(node)
756 common_var = unwrap_node(common_var)
757 switch_node = Nodes.SwitchStatNode(pos = node.pos,
760 else_clause = node.else_clause)
763 def visit_CondExprNode(self, node):
764 not_in, common_var, conditions = self.extract_common_conditions(
765 None, node.test, True)
766 if common_var is None \
767 or len(conditions) < 2 \
768 or self.has_duplicate_values(conditions):
769 self.visitchildren(node)
771 return self.build_simple_switch_statement(
772 node, common_var, conditions, not_in,
773 node.true_val, node.false_val)
775 def visit_BoolBinopNode(self, node):
776 not_in, common_var, conditions = self.extract_common_conditions(
778 if common_var is None \
779 or len(conditions) < 2 \
780 or self.has_duplicate_values(conditions):
781 self.visitchildren(node)
784 return self.build_simple_switch_statement(
785 node, common_var, conditions, not_in,
786 ExprNodes.BoolNode(node.pos, value=True, constant_result=True),
787 ExprNodes.BoolNode(node.pos, value=False, constant_result=False))
789 def visit_PrimaryCmpNode(self, node):
790 not_in, common_var, conditions = self.extract_common_conditions(
792 if common_var is None \
793 or len(conditions) < 2 \
794 or self.has_duplicate_values(conditions):
795 self.visitchildren(node)
798 return self.build_simple_switch_statement(
799 node, common_var, conditions, not_in,
800 ExprNodes.BoolNode(node.pos, value=True, constant_result=True),
801 ExprNodes.BoolNode(node.pos, value=False, constant_result=False))
803 def build_simple_switch_statement(self, node, common_var, conditions,
804 not_in, true_val, false_val):
805 result_ref = UtilNodes.ResultRefNode(node)
806 true_body = Nodes.SingleAssignmentNode(
811 false_body = Nodes.SingleAssignmentNode(
818 true_body, false_body = false_body, true_body
820 cases = [Nodes.SwitchCaseNode(pos = node.pos,
821 conditions = conditions,
824 common_var = unwrap_node(common_var)
825 switch_node = Nodes.SwitchStatNode(pos = node.pos,
828 else_clause = false_body)
829 return UtilNodes.TempResultFromStatNode(result_ref, switch_node)
831 visit_Node = Visitor.VisitorTransform.recurse_to_children
834 class FlattenInListTransform(Visitor.VisitorTransform, SkipDeclarations):
836 This transformation flattens "x in [val1, ..., valn]" into a sequential list
840 def visit_PrimaryCmpNode(self, node):
841 self.visitchildren(node)
842 if node.cascade is not None:
844 elif node.operator == 'in':
847 elif node.operator == 'not_in':
853 if not isinstance(node.operand2, (ExprNodes.TupleNode,
858 args = node.operand2.args
860 return ExprNodes.BoolNode(pos = node.pos, value = node.operator == 'not_in')
862 lhs = UtilNodes.ResultRefNode(node.operand1)
867 if not arg.is_simple():
868 # must evaluate all non-simple RHS before doing the comparisons
869 arg = UtilNodes.LetRefNode(arg)
871 cond = ExprNodes.PrimaryCmpNode(
874 operator = eq_or_neq,
877 conds.append(ExprNodes.TypecastNode(
880 type = PyrexTypes.c_bint_type))
881 def concat(left, right):
882 return ExprNodes.BoolBinopNode(
884 operator = conjunction,
888 condition = reduce(concat, conds)
889 new_node = UtilNodes.EvalWithTempExprNode(lhs, condition)
890 for temp in temps[::-1]:
891 new_node = UtilNodes.EvalWithTempExprNode(temp, new_node)
894 visit_Node = Visitor.VisitorTransform.recurse_to_children
897 class DropRefcountingTransform(Visitor.VisitorTransform):
898 """Drop ref-counting in safe places.
900 visit_Node = Visitor.VisitorTransform.recurse_to_children
902 def visit_ParallelAssignmentNode(self, node):
904 Parallel swap assignments like 'a,b = b,a' are safe.
906 left_names, right_names = [], []
907 left_indices, right_indices = [], []
910 for stat in node.stats:
911 if isinstance(stat, Nodes.SingleAssignmentNode):
912 if not self._extract_operand(stat.lhs, left_names,
913 left_indices, temps):
915 if not self._extract_operand(stat.rhs, right_names,
916 right_indices, temps):
918 elif isinstance(stat, Nodes.CascadedAssignmentNode):
924 if left_names or right_names:
925 # lhs/rhs names must be a non-redundant permutation
926 lnames = [ path for path, n in left_names ]
927 rnames = [ path for path, n in right_names ]
928 if set(lnames) != set(rnames):
930 if len(set(lnames)) != len(right_names):
933 if left_indices or right_indices:
934 # base name and index of index nodes must be a
935 # non-redundant permutation
937 for lhs_node in left_indices:
938 index_id = self._extract_index_id(lhs_node)
941 lindices.append(index_id)
943 for rhs_node in right_indices:
944 index_id = self._extract_index_id(rhs_node)
947 rindices.append(index_id)
949 if set(lindices) != set(rindices):
951 if len(set(lindices)) != len(right_indices):
954 # really supporting IndexNode requires support in
955 # __Pyx_GetItemInt(), so let's stop short for now
958 temp_args = [t.arg for t in temps]
960 temp.use_managed_ref = False
962 for _, name_node in left_names + right_names:
963 if name_node not in temp_args:
964 name_node.use_managed_ref = False
966 for index_node in left_indices + right_indices:
967 index_node.use_managed_ref = False
971 def _extract_operand(self, node, names, indices, temps):
972 node = unwrap_node(node)
973 if not node.type.is_pyobject:
975 if isinstance(node, ExprNodes.CoerceToTempNode):
980 while isinstance(obj_node, ExprNodes.AttributeNode):
981 if obj_node.is_py_attr:
983 name_path.append(obj_node.member)
984 obj_node = obj_node.obj
985 if isinstance(obj_node, ExprNodes.NameNode):
986 name_path.append(obj_node.name)
987 names.append( ('.'.join(name_path[::-1]), node) )
988 elif isinstance(node, ExprNodes.IndexNode):
989 if node.base.type != Builtin.list_type:
991 if not node.index.type.is_int:
993 if not isinstance(node.base, ExprNodes.NameNode):
1000 def _extract_index_id(self, index_node):
1001 base = index_node.base
1002 index = index_node.index
1003 if isinstance(index, ExprNodes.NameNode):
1004 index_val = index.name
1005 elif isinstance(index, ExprNodes.ConstNode):
1010 return (base.name, index_val)
1013 class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
1014 """Optimize some common calls to builtin types *before* the type
1015 analysis phase and *after* the declarations analysis phase.
1017 This transform cannot make use of any argument types, but it can
1018 restructure the tree in a way that the type analysis phase can
1021 Introducing C function calls here may not be a good idea. Move
1022 them to the OptimizeBuiltinCalls transform instead, which runs
1025 # only intercept on call nodes
1026 visit_Node = Visitor.VisitorTransform.recurse_to_children
1028 def visit_SimpleCallNode(self, node):
1029 self.visitchildren(node)
1030 function = node.function
1031 if not self._function_is_builtin_name(function):
1033 return self._dispatch_to_handler(node, function, node.args)
1035 def visit_GeneralCallNode(self, node):
1036 self.visitchildren(node)
1037 function = node.function
1038 if not self._function_is_builtin_name(function):
1040 arg_tuple = node.positional_args
1041 if not isinstance(arg_tuple, ExprNodes.TupleNode):
1043 args = arg_tuple.args
1044 return self._dispatch_to_handler(
1045 node, function, args, node.keyword_args)
1047 def _function_is_builtin_name(self, function):
1048 if not function.is_name:
1050 entry = self.current_env().lookup(function.name)
1051 if entry and getattr(entry, 'scope', None) is not Builtin.builtin_scope:
1053 # if entry is None, it's at least an undeclared name, so likely builtin
1056 def _dispatch_to_handler(self, node, function, args, kwargs=None):
1058 handler_name = '_handle_simple_function_%s' % function.name
1060 handler_name = '_handle_general_function_%s' % function.name
1061 handle_call = getattr(self, handler_name, None)
1062 if handle_call is not None:
1064 return handle_call(node, args)
1066 return handle_call(node, args, kwargs)
1069 def _inject_capi_function(self, node, cname, func_type, utility_code=None):
1070 node.function = ExprNodes.PythonCapiFunctionNode(
1071 node.function.pos, node.function.name, cname, func_type,
1072 utility_code = utility_code)
1074 def _error_wrong_arg_count(self, function_name, node, args, expected=None):
1075 if not expected: # None or 0
1077 elif isinstance(expected, basestring) or expected > 1:
1083 if expected is not None:
1084 expected_str = 'expected %s, ' % expected
1087 error(node.pos, "%s(%s) called with wrong number of args, %sfound %d" % (
1088 function_name, arg_str, expected_str, len(args)))
1090 # specific handlers for simple call nodes
1092 def _handle_simple_function_float(self, node, pos_args):
1093 if len(pos_args) == 0:
1094 return ExprNodes.FloatNode(node.pos, value='0.0')
1095 if len(pos_args) > 1:
1096 self._error_wrong_arg_count('float', node, pos_args, 1)
1099 class YieldNodeCollector(Visitor.TreeVisitor):
1101 Visitor.TreeVisitor.__init__(self)
1102 self.yield_stat_nodes = {}
1103 self.yield_nodes = []
1105 visit_Node = Visitor.TreeVisitor.visitchildren
1106 def visit_YieldExprNode(self, node):
1107 self.yield_nodes.append(node)
1108 self.visitchildren(node)
1110 def visit_ExprStatNode(self, node):
1111 self.visitchildren(node)
1112 if node.expr in self.yield_nodes:
1113 self.yield_stat_nodes[node.expr] = node
1115 def __visit_GeneratorExpressionNode(self, node):
1116 # enable when we support generic generator expressions
1118 # everything below this node is out of scope
1121 def _find_single_yield_expression(self, node):
1122 collector = self.YieldNodeCollector()
1123 collector.visitchildren(node)
1124 if len(collector.yield_nodes) != 1:
1126 yield_node = collector.yield_nodes[0]
1128 return (yield_node.arg, collector.yield_stat_nodes[yield_node])
1132 def _handle_simple_function_all(self, node, pos_args):
1135 _result = all(x for L in LL for x in L)
1150 return self._transform_any_all(node, pos_args, False)
1152 def _handle_simple_function_any(self, node, pos_args):
1155 _result = any(x for L in LL for x in L)
1170 return self._transform_any_all(node, pos_args, True)
1172 def _transform_any_all(self, node, pos_args, is_any):
1173 if len(pos_args) != 1:
1175 if not isinstance(pos_args[0], ExprNodes.GeneratorExpressionNode):
1177 gen_expr_node = pos_args[0]
1178 loop_node = gen_expr_node.loop
1179 yield_expression, yield_stat_node = self._find_single_yield_expression(loop_node)
1180 if yield_expression is None:
1184 condition = yield_expression
1186 condition = ExprNodes.NotNode(yield_expression.pos, operand = yield_expression)
1188 result_ref = UtilNodes.ResultRefNode(pos=node.pos, type=PyrexTypes.c_bint_type)
1189 test_node = Nodes.IfStatNode(
1190 yield_expression.pos,
1192 if_clauses = [ Nodes.IfClauseNode(
1193 yield_expression.pos,
1194 condition = condition,
1195 body = Nodes.StatListNode(
1198 Nodes.SingleAssignmentNode(
1201 rhs = ExprNodes.BoolNode(yield_expression.pos, value = is_any,
1202 constant_result = is_any)),
1203 Nodes.BreakStatNode(node.pos)
1207 while isinstance(loop.body, Nodes.LoopNode):
1208 next_loop = loop.body
1209 loop.body = Nodes.StatListNode(loop.body.pos, stats = [
1211 Nodes.BreakStatNode(yield_expression.pos)
1213 next_loop.else_clause = Nodes.ContinueStatNode(yield_expression.pos)
1215 loop_node.else_clause = Nodes.SingleAssignmentNode(
1218 rhs = ExprNodes.BoolNode(yield_expression.pos, value = not is_any,
1219 constant_result = not is_any))
1221 Visitor.recursively_replace_node(loop_node, yield_stat_node, test_node)
1223 return ExprNodes.InlinedGeneratorExpressionNode(
1224 gen_expr_node.pos, loop = loop_node, result_node = result_ref,
1225 expr_scope = gen_expr_node.expr_scope, orig_func = is_any and 'any' or 'all')
1227 def _handle_simple_function_sum(self, node, pos_args):
1228 """Transform sum(genexpr) into an equivalent inlined aggregation loop.
1230 if len(pos_args) not in (1,2):
1232 if not isinstance(pos_args[0], ExprNodes.GeneratorExpressionNode):
1234 gen_expr_node = pos_args[0]
1235 loop_node = gen_expr_node.loop
1237 yield_expression, yield_stat_node = self._find_single_yield_expression(loop_node)
1238 if yield_expression is None:
1241 if len(pos_args) == 1:
1242 start = ExprNodes.IntNode(node.pos, value='0', constant_result=0)
1246 result_ref = UtilNodes.ResultRefNode(pos=node.pos, type=PyrexTypes.py_object_type)
1247 add_node = Nodes.SingleAssignmentNode(
1248 yield_expression.pos,
1250 rhs = ExprNodes.binop_node(node.pos, '+', result_ref, yield_expression)
1253 Visitor.recursively_replace_node(loop_node, yield_stat_node, add_node)
1255 exec_code = Nodes.StatListNode(
1258 Nodes.SingleAssignmentNode(
1260 lhs = UtilNodes.ResultRefNode(pos=node.pos, expression=result_ref),
1266 return ExprNodes.InlinedGeneratorExpressionNode(
1267 gen_expr_node.pos, loop = exec_code, result_node = result_ref,
1268 expr_scope = gen_expr_node.expr_scope, orig_func = 'sum')
1270 def _handle_simple_function_min(self, node, pos_args):
1271 return self._optimise_min_max(node, pos_args, '<')
1273 def _handle_simple_function_max(self, node, pos_args):
1274 return self._optimise_min_max(node, pos_args, '>')
1276 def _optimise_min_max(self, node, args, operator):
1277 """Replace min(a,b,...) and max(a,b,...) by explicit comparison code.
1280 # leave this to Python
1283 cascaded_nodes = map(UtilNodes.ResultRefNode, args[1:])
1285 last_result = args[0]
1286 for arg_node in cascaded_nodes:
1287 result_ref = UtilNodes.ResultRefNode(last_result)
1288 last_result = ExprNodes.CondExprNode(
1290 true_val = arg_node,
1291 false_val = result_ref,
1292 test = ExprNodes.PrimaryCmpNode(
1294 operand1 = arg_node,
1295 operator = operator,
1296 operand2 = result_ref,
1299 last_result = UtilNodes.EvalWithTempExprNode(result_ref, last_result)
1301 for ref_node in cascaded_nodes[::-1]:
1302 last_result = UtilNodes.EvalWithTempExprNode(ref_node, last_result)
1306 def _DISABLED_handle_simple_function_tuple(self, node, pos_args):
1307 if len(pos_args) == 0:
1308 return ExprNodes.TupleNode(node.pos, args=[], constant_result=())
1309 # This is a bit special - for iterables (including genexps),
1310 # Python actually overallocates and resizes a newly created
1311 # tuple incrementally while reading items, which we can't
1312 # easily do without explicit node support. Instead, we read
1313 # the items into a list and then copy them into a tuple of the
1314 # final size. This takes up to twice as much memory, but will
1315 # have to do until we have real support for genexps.
1316 result = self._transform_list_set_genexpr(node, pos_args, ExprNodes.ListNode)
1317 if result is not node:
1318 return ExprNodes.AsTupleNode(node.pos, arg=result)
1321 def _handle_simple_function_list(self, node, pos_args):
1322 if len(pos_args) == 0:
1323 return ExprNodes.ListNode(node.pos, args=[], constant_result=[])
1324 return self._transform_list_set_genexpr(node, pos_args, ExprNodes.ListNode)
1326 def _handle_simple_function_set(self, node, pos_args):
1327 if len(pos_args) == 0:
1328 return ExprNodes.SetNode(node.pos, args=[], constant_result=set())
1329 return self._transform_list_set_genexpr(node, pos_args, ExprNodes.SetNode)
1331 def _transform_list_set_genexpr(self, node, pos_args, container_node_class):
1332 """Replace set(genexpr) and list(genexpr) by a literal comprehension.
1334 if len(pos_args) > 1:
1336 if not isinstance(pos_args[0], ExprNodes.GeneratorExpressionNode):
1338 gen_expr_node = pos_args[0]
1339 loop_node = gen_expr_node.loop
1341 yield_expression, yield_stat_node = self._find_single_yield_expression(loop_node)
1342 if yield_expression is None:
1345 target_node = container_node_class(node.pos, args=[])
1346 append_node = ExprNodes.ComprehensionAppendNode(
1347 yield_expression.pos,
1348 expr = yield_expression,
1349 target = ExprNodes.CloneNode(target_node))
1351 Visitor.recursively_replace_node(loop_node, yield_stat_node, append_node)
1353 setcomp = ExprNodes.ComprehensionNode(
1355 has_local_scope = True,
1356 expr_scope = gen_expr_node.expr_scope,
1358 append = append_node,
1359 target = target_node)
1360 append_node.target = setcomp
1363 def _handle_simple_function_dict(self, node, pos_args):
1364 """Replace dict( (a,b) for ... ) by a literal { a:b for ... }.
1366 if len(pos_args) == 0:
1367 return ExprNodes.DictNode(node.pos, key_value_pairs=[], constant_result={})
1368 if len(pos_args) > 1:
1370 if not isinstance(pos_args[0], ExprNodes.GeneratorExpressionNode):
1372 gen_expr_node = pos_args[0]
1373 loop_node = gen_expr_node.loop
1375 yield_expression, yield_stat_node = self._find_single_yield_expression(loop_node)
1376 if yield_expression is None:
1379 if not isinstance(yield_expression, ExprNodes.TupleNode):
1381 if len(yield_expression.args) != 2:
1384 target_node = ExprNodes.DictNode(node.pos, key_value_pairs=[])
1385 append_node = ExprNodes.DictComprehensionAppendNode(
1386 yield_expression.pos,
1387 key_expr = yield_expression.args[0],
1388 value_expr = yield_expression.args[1],
1389 target = ExprNodes.CloneNode(target_node))
1391 Visitor.recursively_replace_node(loop_node, yield_stat_node, append_node)
1393 dictcomp = ExprNodes.ComprehensionNode(
1395 has_local_scope = True,
1396 expr_scope = gen_expr_node.expr_scope,
1398 append = append_node,
1399 target = target_node)
1400 append_node.target = dictcomp
1403 # specific handlers for general call nodes
1405 def _handle_general_function_dict(self, node, pos_args, kwargs):
1406 """Replace dict(a=b,c=d,...) by the underlying keyword dict
1407 construction which is done anyway.
1409 if len(pos_args) > 0:
1411 if not isinstance(kwargs, ExprNodes.DictNode):
1413 if node.starstar_arg:
1414 # we could optimize this by updating the kw dict instead
1419 class OptimizeBuiltinCalls(Visitor.EnvTransform):
1420 """Optimize some common methods calls and instantiation patterns
1421 for builtin types *after* the type analysis phase.
1423 Running after type analysis, this transform can only perform
1424 function replacements that do not alter the function return type
1425 in a way that was not anticipated by the type analysis.
1427 # only intercept on call nodes
1428 visit_Node = Visitor.VisitorTransform.recurse_to_children
1430 def visit_GeneralCallNode(self, node):
1431 self.visitchildren(node)
1432 function = node.function
1433 if not function.type.is_pyobject:
1435 arg_tuple = node.positional_args
1436 if not isinstance(arg_tuple, ExprNodes.TupleNode):
1438 if node.starstar_arg:
1440 args = arg_tuple.args
1441 return self._dispatch_to_handler(
1442 node, function, args, node.keyword_args)
1444 def visit_SimpleCallNode(self, node):
1445 self.visitchildren(node)
1446 function = node.function
1447 if function.type.is_pyobject:
1448 arg_tuple = node.arg_tuple
1449 if not isinstance(arg_tuple, ExprNodes.TupleNode):
1451 args = arg_tuple.args
1454 return self._dispatch_to_handler(
1455 node, function, args)
1457 ### cleanup to avoid redundant coercions to/from Python types
1459 def _visit_PyTypeTestNode(self, node):
1460 # disabled - appears to break assignments in some cases, and
1461 # also drops a None check, which might still be required
1462 """Flatten redundant type checks after tree changes.
1465 self.visitchildren(node)
1466 if old_arg is node.arg or node.arg.type != node.type:
1470 def visit_TypecastNode(self, node):
1472 Drop redundant type casts.
1474 self.visitchildren(node)
1475 if node.type == node.operand.type:
1479 def visit_CoerceToBooleanNode(self, node):
1480 """Drop redundant conversion nodes after tree changes.
1482 self.visitchildren(node)
1484 if isinstance(arg, ExprNodes.PyTypeTestNode):
1486 if isinstance(arg, ExprNodes.CoerceToPyTypeNode):
1487 if arg.type in (PyrexTypes.py_object_type, Builtin.bool_type):
1488 return arg.arg.coerce_to_boolean(self.current_env())
1491 def visit_CoerceFromPyTypeNode(self, node):
1492 """Drop redundant conversion nodes after tree changes.
1494 Also, optimise away calls to Python's builtin int() and
1495 float() if the result is going to be coerced back into a C
1498 self.visitchildren(node)
1500 if not arg.type.is_pyobject:
1501 # no Python conversion left at all, just do a C coercion instead
1502 if node.type == arg.type:
1505 return arg.coerce_to(node.type, self.current_env())
1506 if isinstance(arg, ExprNodes.PyTypeTestNode):
1508 if isinstance(arg, ExprNodes.CoerceToPyTypeNode):
1509 if arg.type is PyrexTypes.py_object_type:
1510 if node.type.assignable_from(arg.arg.type):
1511 # completely redundant C->Py->C coercion
1512 return arg.arg.coerce_to(node.type, self.current_env())
1513 if isinstance(arg, ExprNodes.SimpleCallNode):
1514 if node.type.is_int or node.type.is_float:
1515 return self._optimise_numeric_cast_call(node, arg)
1516 elif isinstance(arg, ExprNodes.IndexNode) and not arg.is_buffer_access:
1517 index_node = arg.index
1518 if isinstance(index_node, ExprNodes.CoerceToPyTypeNode):
1519 index_node = index_node.arg
1520 if index_node.type.is_int:
1521 return self._optimise_int_indexing(node, arg, index_node)
1524 PyBytes_GetItemInt_func_type = PyrexTypes.CFuncType(
1525 PyrexTypes.c_char_type, [
1526 PyrexTypes.CFuncTypeArg("bytes", Builtin.bytes_type, None),
1527 PyrexTypes.CFuncTypeArg("index", PyrexTypes.c_py_ssize_t_type, None),
1528 PyrexTypes.CFuncTypeArg("check_bounds", PyrexTypes.c_int_type, None),
1530 exception_value = "((char)-1)",
1531 exception_check = True)
1533 def _optimise_int_indexing(self, coerce_node, arg, index_node):
1534 env = self.current_env()
1535 bound_check_bool = env.directives['boundscheck'] and 1 or 0
1536 if arg.base.type is Builtin.bytes_type:
1537 if coerce_node.type in (PyrexTypes.c_char_type, PyrexTypes.c_uchar_type):
1538 # bytes[index] -> char
1539 bound_check_node = ExprNodes.IntNode(
1540 coerce_node.pos, value=str(bound_check_bool),
1541 constant_result=bound_check_bool)
1542 node = ExprNodes.PythonCapiCallNode(
1543 coerce_node.pos, "__Pyx_PyBytes_GetItemInt",
1544 self.PyBytes_GetItemInt_func_type,
1546 arg.base.as_none_safe_node("'NoneType' object is not subscriptable"),
1547 index_node.coerce_to(PyrexTypes.c_py_ssize_t_type, env),
1551 utility_code=bytes_index_utility_code)
1552 if coerce_node.type is not PyrexTypes.c_char_type:
1553 node = node.coerce_to(coerce_node.type, env)
1557 def _optimise_numeric_cast_call(self, node, arg):
1558 function = arg.function
1559 if not isinstance(function, ExprNodes.NameNode) \
1560 or not function.type.is_builtin_type \
1561 or not isinstance(arg.arg_tuple, ExprNodes.TupleNode):
1563 args = arg.arg_tuple.args
1567 if isinstance(func_arg, ExprNodes.CoerceToPyTypeNode):
1568 func_arg = func_arg.arg
1569 elif func_arg.type.is_pyobject:
1570 # play safe: Python conversion might work on all sorts of things
1572 if function.name == 'int':
1573 if func_arg.type.is_int or node.type.is_int:
1574 if func_arg.type == node.type:
1576 elif node.type.assignable_from(func_arg.type) or func_arg.type.is_float:
1577 return ExprNodes.TypecastNode(
1578 node.pos, operand=func_arg, type=node.type)
1579 elif function.name == 'float':
1580 if func_arg.type.is_float or node.type.is_float:
1581 if func_arg.type == node.type:
1583 elif node.type.assignable_from(func_arg.type) or func_arg.type.is_float:
1584 return ExprNodes.TypecastNode(
1585 node.pos, operand=func_arg, type=node.type)
1588 ### dispatch to specific optimisers
1590 def _find_handler(self, match_name, has_kwargs):
1591 call_type = has_kwargs and 'general' or 'simple'
1592 handler = getattr(self, '_handle_%s_%s' % (call_type, match_name), None)
1594 handler = getattr(self, '_handle_any_%s' % match_name, None)
1597 def _dispatch_to_handler(self, node, function, arg_list, kwargs=None):
1598 if function.is_name:
1599 # we only consider functions that are either builtin
1600 # Python functions or builtins that were already replaced
1601 # into a C function call (defined in the builtin scope)
1602 if not function.entry:
1604 is_builtin = function.entry.is_builtin \
1605 or getattr(function.entry, 'scope', None) is Builtin.builtin_scope
1608 function_handler = self._find_handler(
1609 "function_%s" % function.name, kwargs)
1610 if function_handler is None:
1613 return function_handler(node, arg_list, kwargs)
1615 return function_handler(node, arg_list)
1616 elif function.is_attribute and function.type.is_pyobject:
1617 attr_name = function.attribute
1618 self_arg = function.obj
1619 obj_type = self_arg.type
1620 is_unbound_method = False
1621 if obj_type.is_builtin_type:
1622 if obj_type is Builtin.type_type and arg_list and \
1623 arg_list[0].type.is_pyobject:
1624 # calling an unbound method like 'list.append(L,x)'
1625 # (ignoring 'type.mro()' here ...)
1626 type_name = function.obj.name
1628 is_unbound_method = True
1630 type_name = obj_type.name
1632 type_name = "object" # safety measure
1633 method_handler = self._find_handler(
1634 "method_%s_%s" % (type_name, attr_name), kwargs)
1635 if method_handler is None:
1636 if attr_name in TypeSlots.method_name_to_slot \
1637 or attr_name == '__new__':
1638 method_handler = self._find_handler(
1639 "slot%s" % attr_name, kwargs)
1640 if method_handler is None:
1642 if self_arg is not None:
1643 arg_list = [self_arg] + list(arg_list)
1645 return method_handler(node, arg_list, kwargs, is_unbound_method)
1647 return method_handler(node, arg_list, is_unbound_method)
1651 def _error_wrong_arg_count(self, function_name, node, args, expected=None):
1652 if not expected: # None or 0
1654 elif isinstance(expected, basestring) or expected > 1:
1660 if expected is not None:
1661 expected_str = 'expected %s, ' % expected
1664 error(node.pos, "%s(%s) called with wrong number of args, %sfound %d" % (
1665 function_name, arg_str, expected_str, len(args)))
1669 PyDict_Copy_func_type = PyrexTypes.CFuncType(
1670 Builtin.dict_type, [
1671 PyrexTypes.CFuncTypeArg("dict", Builtin.dict_type, None)
1674 def _handle_simple_function_dict(self, node, pos_args):
1675 """Replace dict(some_dict) by PyDict_Copy(some_dict).
1677 if len(pos_args) != 1:
1680 if arg.type is Builtin.dict_type:
1681 arg = arg.as_none_safe_node("'NoneType' is not iterable")
1682 return ExprNodes.PythonCapiCallNode(
1683 node.pos, "PyDict_Copy", self.PyDict_Copy_func_type,
1685 is_temp = node.is_temp
1689 PyList_AsTuple_func_type = PyrexTypes.CFuncType(
1690 Builtin.tuple_type, [
1691 PyrexTypes.CFuncTypeArg("list", Builtin.list_type, None)
1694 def _handle_simple_function_tuple(self, node, pos_args):
1695 """Replace tuple([...]) by a call to PyList_AsTuple.
1697 if len(pos_args) != 1:
1699 list_arg = pos_args[0]
1700 if list_arg.type is not Builtin.list_type:
1702 if not isinstance(list_arg, (ExprNodes.ComprehensionNode,
1703 ExprNodes.ListNode)):
1704 pos_args[0] = list_arg.as_none_safe_node(
1705 "'NoneType' object is not iterable")
1707 return ExprNodes.PythonCapiCallNode(
1708 node.pos, "PyList_AsTuple", self.PyList_AsTuple_func_type,
1710 is_temp = node.is_temp
1713 PyObject_AsDouble_func_type = PyrexTypes.CFuncType(
1714 PyrexTypes.c_double_type, [
1715 PyrexTypes.CFuncTypeArg("obj", PyrexTypes.py_object_type, None),
1717 exception_value = "((double)-1)",
1718 exception_check = True)
1720 def _handle_simple_function_float(self, node, pos_args):
1721 """Transform float() into either a C type cast or a faster C
1724 # Note: this requires the float() function to be typed as
1725 # returning a C 'double'
1726 if len(pos_args) == 0:
1727 return ExprNode.FloatNode(
1728 node, value="0.0", constant_result=0.0
1729 ).coerce_to(Builtin.float_type, self.current_env())
1730 elif len(pos_args) != 1:
1731 self._error_wrong_arg_count('float', node, pos_args, '0 or 1')
1733 func_arg = pos_args[0]
1734 if isinstance(func_arg, ExprNodes.CoerceToPyTypeNode):
1735 func_arg = func_arg.arg
1736 if func_arg.type is PyrexTypes.c_double_type:
1738 elif node.type.assignable_from(func_arg.type) or func_arg.type.is_numeric:
1739 return ExprNodes.TypecastNode(
1740 node.pos, operand=func_arg, type=node.type)
1741 return ExprNodes.PythonCapiCallNode(
1742 node.pos, "__Pyx_PyObject_AsDouble",
1743 self.PyObject_AsDouble_func_type,
1745 is_temp = node.is_temp,
1746 utility_code = pyobject_as_double_utility_code,
1749 def _handle_simple_function_bool(self, node, pos_args):
1750 """Transform bool(x) into a type coercion to a boolean.
1752 if len(pos_args) == 0:
1753 return ExprNodes.BoolNode(
1754 node.pos, value=False, constant_result=False
1755 ).coerce_to(Builtin.bool_type, self.current_env())
1756 elif len(pos_args) != 1:
1757 self._error_wrong_arg_count('bool', node, pos_args, '0 or 1')
1760 return pos_args[0].coerce_to_boolean(
1761 self.current_env()).coerce_to_pyobject(self.current_env())
1763 ### builtin functions
1765 PyObject_GetAttr2_func_type = PyrexTypes.CFuncType(
1766 PyrexTypes.py_object_type, [
1767 PyrexTypes.CFuncTypeArg("object", PyrexTypes.py_object_type, None),
1768 PyrexTypes.CFuncTypeArg("attr_name", PyrexTypes.py_object_type, None),
1771 PyObject_GetAttr3_func_type = PyrexTypes.CFuncType(
1772 PyrexTypes.py_object_type, [
1773 PyrexTypes.CFuncTypeArg("object", PyrexTypes.py_object_type, None),
1774 PyrexTypes.CFuncTypeArg("attr_name", PyrexTypes.py_object_type, None),
1775 PyrexTypes.CFuncTypeArg("default", PyrexTypes.py_object_type, None),
1778 def _handle_simple_function_getattr(self, node, pos_args):
1779 """Replace 2/3 argument forms of getattr() by C-API calls.
1781 if len(pos_args) == 2:
1782 return ExprNodes.PythonCapiCallNode(
1783 node.pos, "PyObject_GetAttr", self.PyObject_GetAttr2_func_type,
1785 may_return_none = True,
1786 is_temp = node.is_temp)
1787 elif len(pos_args) == 3:
1788 return ExprNodes.PythonCapiCallNode(
1789 node.pos, "__Pyx_GetAttr3", self.PyObject_GetAttr3_func_type,
1791 may_return_none = True,
1792 is_temp = node.is_temp,
1793 utility_code = Builtin.getattr3_utility_code)
1795 self._error_wrong_arg_count('getattr', node, pos_args, '2 or 3')
1798 PyObject_GetIter_func_type = PyrexTypes.CFuncType(
1799 PyrexTypes.py_object_type, [
1800 PyrexTypes.CFuncTypeArg("object", PyrexTypes.py_object_type, None),
1803 PyCallIter_New_func_type = PyrexTypes.CFuncType(
1804 PyrexTypes.py_object_type, [
1805 PyrexTypes.CFuncTypeArg("object", PyrexTypes.py_object_type, None),
1806 PyrexTypes.CFuncTypeArg("sentinel", PyrexTypes.py_object_type, None),
1809 def _handle_simple_function_iter(self, node, pos_args):
1810 """Replace 1/2 argument forms of iter() by C-API calls.
1812 if len(pos_args) == 1:
1813 return ExprNodes.PythonCapiCallNode(
1814 node.pos, "PyObject_GetIter", self.PyObject_GetIter_func_type,
1816 may_return_none = True,
1817 is_temp = node.is_temp)
1818 elif len(pos_args) == 2:
1819 return ExprNodes.PythonCapiCallNode(
1820 node.pos, "PyCallIter_New", self.PyCallIter_New_func_type,
1822 is_temp = node.is_temp)
1824 self._error_wrong_arg_count('iter', node, pos_args, '1 or 2')
1827 Pyx_strlen_func_type = PyrexTypes.CFuncType(
1828 PyrexTypes.c_size_t_type, [
1829 PyrexTypes.CFuncTypeArg("bytes", PyrexTypes.c_char_ptr_type, None)
1832 PyObject_Size_func_type = PyrexTypes.CFuncType(
1833 PyrexTypes.c_py_ssize_t_type, [
1834 PyrexTypes.CFuncTypeArg("obj", PyrexTypes.py_object_type, None)
1837 _map_to_capi_len_function = {
1838 Builtin.unicode_type : "PyUnicode_GET_SIZE",
1839 Builtin.bytes_type : "PyBytes_GET_SIZE",
1840 Builtin.list_type : "PyList_GET_SIZE",
1841 Builtin.tuple_type : "PyTuple_GET_SIZE",
1842 Builtin.dict_type : "PyDict_Size",
1843 Builtin.set_type : "PySet_Size",
1844 Builtin.frozenset_type : "PySet_Size",
1847 def _handle_simple_function_len(self, node, pos_args):
1848 """Replace len(char*) by the equivalent call to strlen() and
1849 len(known_builtin_type) by an equivalent C-API call.
1851 if len(pos_args) != 1:
1852 self._error_wrong_arg_count('len', node, pos_args, 1)
1855 if isinstance(arg, ExprNodes.CoerceToPyTypeNode):
1857 if arg.type.is_string:
1858 new_node = ExprNodes.PythonCapiCallNode(
1859 node.pos, "strlen", self.Pyx_strlen_func_type,
1861 is_temp = node.is_temp,
1862 utility_code = include_string_h_utility_code)
1863 elif arg.type.is_pyobject:
1864 cfunc_name = self._map_to_capi_len_function(arg.type)
1865 if cfunc_name is None:
1867 arg = arg.as_none_safe_node(
1868 "object of type 'NoneType' has no len()")
1869 new_node = ExprNodes.PythonCapiCallNode(
1870 node.pos, cfunc_name, self.PyObject_Size_func_type,
1872 is_temp = node.is_temp)
1873 elif arg.type is PyrexTypes.c_py_unicode_type:
1874 return ExprNodes.IntNode(node.pos, value='1', constant_result=1,
1878 if node.type not in (PyrexTypes.c_size_t_type, PyrexTypes.c_py_ssize_t_type):
1879 new_node = new_node.coerce_to(node.type, self.current_env())
1882 Pyx_Type_func_type = PyrexTypes.CFuncType(
1883 Builtin.type_type, [
1884 PyrexTypes.CFuncTypeArg("object", PyrexTypes.py_object_type, None)
1887 def _handle_simple_function_type(self, node, pos_args):
1888 """Replace type(o) by a macro call to Py_TYPE(o).
1890 if len(pos_args) != 1:
1892 node = ExprNodes.PythonCapiCallNode(
1893 node.pos, "Py_TYPE", self.Pyx_Type_func_type,
1896 return ExprNodes.CastNode(node, PyrexTypes.py_object_type)
1898 Py_type_check_func_type = PyrexTypes.CFuncType(
1899 PyrexTypes.c_bint_type, [
1900 PyrexTypes.CFuncTypeArg("arg", PyrexTypes.py_object_type, None)
1903 def _handle_simple_function_isinstance(self, node, pos_args):
1904 """Replace isinstance() checks against builtin types by the
1905 corresponding C-API call.
1907 if len(pos_args) != 2:
1909 arg, types = pos_args
1911 if isinstance(types, ExprNodes.TupleNode):
1913 arg = temp = UtilNodes.ResultRefNode(arg)
1914 elif types.type is Builtin.type_type:
1921 env = self.current_env()
1922 for test_type_node in types:
1923 if not test_type_node.entry:
1925 entry = env.lookup(test_type_node.entry.name)
1926 if not entry or not entry.type or not entry.type.is_builtin_type:
1928 type_check_function = entry.type.type_check_function(exact=False)
1929 if not type_check_function:
1931 if type_check_function not in tests:
1932 tests.append(type_check_function)
1934 ExprNodes.PythonCapiCallNode(
1935 test_type_node.pos, type_check_function, self.Py_type_check_func_type,
1940 def join_with_or(a,b, make_binop_node=ExprNodes.binop_node):
1941 or_node = make_binop_node(node.pos, 'or', a, b)
1942 or_node.type = PyrexTypes.c_bint_type
1943 or_node.is_temp = True
1946 test_node = reduce(join_with_or, test_nodes).coerce_to(node.type, env)
1947 if temp is not None:
1948 test_node = UtilNodes.EvalWithTempExprNode(temp, test_node)
1951 def _handle_simple_function_ord(self, node, pos_args):
1952 """Unpack ord(Py_UNICODE).
1954 if len(pos_args) != 1:
1957 if isinstance(arg, ExprNodes.CoerceToPyTypeNode):
1958 if arg.arg.type is PyrexTypes.c_py_unicode_type:
1959 return arg.arg.coerce_to(node.type, self.current_env())
1964 Pyx_tp_new_func_type = PyrexTypes.CFuncType(
1965 PyrexTypes.py_object_type, [
1966 PyrexTypes.CFuncTypeArg("type", Builtin.type_type, None)
1969 def _handle_simple_slot__new__(self, node, args, is_unbound_method):
1970 """Replace 'exttype.__new__(exttype)' by a call to exttype->tp_new()
1972 obj = node.function.obj
1973 if not is_unbound_method or len(args) != 1:
1976 if not obj.is_name or not type_arg.is_name:
1979 if obj.type != Builtin.type_type or type_arg.type != Builtin.type_type:
1980 # not a known type, play safe
1982 if not type_arg.type_entry or not obj.type_entry:
1983 if obj.name != type_arg.name:
1985 # otherwise, we know it's a type and we know it's the same
1986 # type for both - that should do
1987 elif type_arg.type_entry != obj.type_entry:
1988 # different types - may or may not lead to an error at runtime
1991 # FIXME: we could potentially look up the actual tp_new C
1992 # method of the extension type and call that instead of the
1993 # generic slot. That would also allow us to pass parameters
1996 if not type_arg.type_entry:
1997 # arbitrary variable, needs a None check for safety
1998 type_arg = type_arg.as_none_safe_node(
1999 "object.__new__(X): X is not a type object (NoneType)")
2001 return ExprNodes.PythonCapiCallNode(
2002 node.pos, "__Pyx_tp_new", self.Pyx_tp_new_func_type,
2004 utility_code = tpnew_utility_code,
2005 is_temp = node.is_temp
2008 ### methods of builtin types
2010 PyObject_Append_func_type = PyrexTypes.CFuncType(
2011 PyrexTypes.py_object_type, [
2012 PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None),
2013 PyrexTypes.CFuncTypeArg("item", PyrexTypes.py_object_type, None),
2016 def _handle_simple_method_object_append(self, node, args, is_unbound_method):
2017 """Optimistic optimisation as X.append() is almost always
2018 referring to a list.
2023 return ExprNodes.PythonCapiCallNode(
2024 node.pos, "__Pyx_PyObject_Append", self.PyObject_Append_func_type,
2026 may_return_none = True,
2027 is_temp = node.is_temp,
2028 utility_code = append_utility_code
2031 PyObject_Pop_func_type = PyrexTypes.CFuncType(
2032 PyrexTypes.py_object_type, [
2033 PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None),
2036 PyObject_PopIndex_func_type = PyrexTypes.CFuncType(
2037 PyrexTypes.py_object_type, [
2038 PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None),
2039 PyrexTypes.CFuncTypeArg("index", PyrexTypes.c_long_type, None),
2042 def _handle_simple_method_object_pop(self, node, args, is_unbound_method):
2043 """Optimistic optimisation as X.pop([n]) is almost always
2044 referring to a list.
2047 return ExprNodes.PythonCapiCallNode(
2048 node.pos, "__Pyx_PyObject_Pop", self.PyObject_Pop_func_type,
2050 may_return_none = True,
2051 is_temp = node.is_temp,
2052 utility_code = pop_utility_code
2054 elif len(args) == 2:
2055 if isinstance(args[1], ExprNodes.CoerceToPyTypeNode) and args[1].arg.type.is_int:
2056 original_type = args[1].arg.type
2057 if PyrexTypes.widest_numeric_type(original_type, PyrexTypes.c_py_ssize_t_type) == PyrexTypes.c_py_ssize_t_type:
2058 args[1] = args[1].arg
2059 return ExprNodes.PythonCapiCallNode(
2060 node.pos, "__Pyx_PyObject_PopIndex", self.PyObject_PopIndex_func_type,
2062 may_return_none = True,
2063 is_temp = node.is_temp,
2064 utility_code = pop_index_utility_code
2069 _handle_simple_method_list_pop = _handle_simple_method_object_pop
2071 PyList_Append_func_type = PyrexTypes.CFuncType(
2072 PyrexTypes.c_int_type, [
2073 PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None),
2074 PyrexTypes.CFuncTypeArg("item", PyrexTypes.py_object_type, None),
2076 exception_value = "-1")
2078 def _handle_simple_method_list_append(self, node, args, is_unbound_method):
2079 """Call PyList_Append() instead of l.append().
2082 self._error_wrong_arg_count('list.append', node, args, 2)
2084 return self._substitute_method_call(
2085 node, "PyList_Append", self.PyList_Append_func_type,
2086 'append', is_unbound_method, args)
2088 single_param_func_type = PyrexTypes.CFuncType(
2089 PyrexTypes.c_int_type, [
2090 PyrexTypes.CFuncTypeArg("obj", PyrexTypes.py_object_type, None),
2092 exception_value = "-1")
2094 def _handle_simple_method_list_sort(self, node, args, is_unbound_method):
2095 """Call PyList_Sort() instead of the 0-argument l.sort().
2099 return self._substitute_method_call(
2100 node, "PyList_Sort", self.single_param_func_type,
2101 'sort', is_unbound_method, args)
2103 def _handle_simple_method_list_reverse(self, node, args, is_unbound_method):
2104 """Call PyList_Reverse() instead of l.reverse().
2107 self._error_wrong_arg_count('list.reverse', node, args, 1)
2109 return self._substitute_method_call(
2110 node, "PyList_Reverse", self.single_param_func_type,
2111 'reverse', is_unbound_method, args)
2113 Pyx_PyDict_GetItem_func_type = PyrexTypes.CFuncType(
2114 PyrexTypes.py_object_type, [
2115 PyrexTypes.CFuncTypeArg("dict", PyrexTypes.py_object_type, None),
2116 PyrexTypes.CFuncTypeArg("key", PyrexTypes.py_object_type, None),
2117 PyrexTypes.CFuncTypeArg("default", PyrexTypes.py_object_type, None),
2120 def _handle_simple_method_dict_get(self, node, args, is_unbound_method):
2121 """Replace dict.get() by a call to PyDict_GetItem().
2124 args.append(ExprNodes.NoneNode(node.pos))
2125 elif len(args) != 3:
2126 self._error_wrong_arg_count('dict.get', node, args, "2 or 3")
2129 return self._substitute_method_call(
2130 node, "__Pyx_PyDict_GetItemDefault", self.Pyx_PyDict_GetItem_func_type,
2131 'get', is_unbound_method, args,
2132 may_return_none = True,
2133 utility_code = dict_getitem_default_utility_code)
2136 ### unicode type methods
2138 PyUnicode_uchar_predicate_func_type = PyrexTypes.CFuncType(
2139 PyrexTypes.c_bint_type, [
2140 PyrexTypes.CFuncTypeArg("uchar", PyrexTypes.c_py_unicode_type, None),
2143 def _inject_unicode_predicate(self, node, args, is_unbound_method):
2144 if is_unbound_method or len(args) != 1:
2147 if not isinstance(ustring, ExprNodes.CoerceToPyTypeNode) or \
2148 ustring.arg.type is not PyrexTypes.c_py_unicode_type:
2151 method_name = node.function.attribute
2152 if method_name == 'istitle':
2153 # istitle() doesn't directly map to Py_UNICODE_ISTITLE()
2154 utility_code = py_unicode_istitle_utility_code
2155 function_name = '__Pyx_Py_UNICODE_ISTITLE'
2158 function_name = 'Py_UNICODE_%s' % method_name.upper()
2159 func_call = self._substitute_method_call(
2160 node, function_name, self.PyUnicode_uchar_predicate_func_type,
2161 method_name, is_unbound_method, [uchar],
2162 utility_code = utility_code)
2163 if node.type.is_pyobject:
2164 func_call = func_call.coerce_to_pyobject(self.current_env)
2167 _handle_simple_method_unicode_isalnum = _inject_unicode_predicate
2168 _handle_simple_method_unicode_isalpha = _inject_unicode_predicate
2169 _handle_simple_method_unicode_isdecimal = _inject_unicode_predicate
2170 _handle_simple_method_unicode_isdigit = _inject_unicode_predicate
2171 _handle_simple_method_unicode_islower = _inject_unicode_predicate
2172 _handle_simple_method_unicode_isnumeric = _inject_unicode_predicate
2173 _handle_simple_method_unicode_isspace = _inject_unicode_predicate
2174 _handle_simple_method_unicode_istitle = _inject_unicode_predicate
2175 _handle_simple_method_unicode_isupper = _inject_unicode_predicate
2177 PyUnicode_uchar_conversion_func_type = PyrexTypes.CFuncType(
2178 PyrexTypes.c_py_unicode_type, [
2179 PyrexTypes.CFuncTypeArg("uchar", PyrexTypes.c_py_unicode_type, None),
2182 def _inject_unicode_character_conversion(self, node, args, is_unbound_method):
2183 if is_unbound_method or len(args) != 1:
2186 if not isinstance(ustring, ExprNodes.CoerceToPyTypeNode) or \
2187 ustring.arg.type is not PyrexTypes.c_py_unicode_type:
2190 method_name = node.function.attribute
2191 function_name = 'Py_UNICODE_TO%s' % method_name.upper()
2192 func_call = self._substitute_method_call(
2193 node, function_name, self.PyUnicode_uchar_conversion_func_type,
2194 method_name, is_unbound_method, [uchar])
2195 if node.type.is_pyobject:
2196 func_call = func_call.coerce_to_pyobject(self.current_env)
2199 _handle_simple_method_unicode_lower = _inject_unicode_character_conversion
2200 _handle_simple_method_unicode_upper = _inject_unicode_character_conversion
2201 _handle_simple_method_unicode_title = _inject_unicode_character_conversion
2203 PyUnicode_Splitlines_func_type = PyrexTypes.CFuncType(
2204 Builtin.list_type, [
2205 PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
2206 PyrexTypes.CFuncTypeArg("keepends", PyrexTypes.c_bint_type, None),
2209 def _handle_simple_method_unicode_splitlines(self, node, args, is_unbound_method):
2210 """Replace unicode.splitlines(...) by a direct call to the
2211 corresponding C-API function.
2213 if len(args) not in (1,2):
2214 self._error_wrong_arg_count('unicode.splitlines', node, args, "1 or 2")
2216 self._inject_bint_default_argument(node, args, 1, False)
2218 return self._substitute_method_call(
2219 node, "PyUnicode_Splitlines", self.PyUnicode_Splitlines_func_type,
2220 'splitlines', is_unbound_method, args)
2222 PyUnicode_Join_func_type = PyrexTypes.CFuncType(
2223 Builtin.unicode_type, [
2224 PyrexTypes.CFuncTypeArg("sep", Builtin.unicode_type, None),
2225 PyrexTypes.CFuncTypeArg("iterable", PyrexTypes.py_object_type, None),
2228 def _handle_simple_method_unicode_join(self, node, args, is_unbound_method):
2229 """Replace unicode.join(...) by a direct call to the
2230 corresponding C-API function.
2233 self._error_wrong_arg_count('unicode.join', node, args, 2)
2236 return self._substitute_method_call(
2237 node, "PyUnicode_Join", self.PyUnicode_Join_func_type,
2238 'join', is_unbound_method, args)
2240 PyUnicode_Split_func_type = PyrexTypes.CFuncType(
2241 Builtin.list_type, [
2242 PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
2243 PyrexTypes.CFuncTypeArg("sep", PyrexTypes.py_object_type, None),
2244 PyrexTypes.CFuncTypeArg("maxsplit", PyrexTypes.c_py_ssize_t_type, None),
2248 def _handle_simple_method_unicode_split(self, node, args, is_unbound_method):
2249 """Replace unicode.split(...) by a direct call to the
2250 corresponding C-API function.
2252 if len(args) not in (1,2,3):
2253 self._error_wrong_arg_count('unicode.split', node, args, "1-3")
2256 args.append(ExprNodes.NullNode(node.pos))
2257 self._inject_int_default_argument(
2258 node, args, 2, PyrexTypes.c_py_ssize_t_type, "-1")
2260 return self._substitute_method_call(
2261 node, "PyUnicode_Split", self.PyUnicode_Split_func_type,
2262 'split', is_unbound_method, args)
2264 PyUnicode_Tailmatch_func_type = PyrexTypes.CFuncType(
2265 PyrexTypes.c_bint_type, [
2266 PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
2267 PyrexTypes.CFuncTypeArg("substring", PyrexTypes.py_object_type, None),
2268 PyrexTypes.CFuncTypeArg("start", PyrexTypes.c_py_ssize_t_type, None),
2269 PyrexTypes.CFuncTypeArg("end", PyrexTypes.c_py_ssize_t_type, None),
2270 PyrexTypes.CFuncTypeArg("direction", PyrexTypes.c_int_type, None),
2272 exception_value = '-1')
2274 def _handle_simple_method_unicode_endswith(self, node, args, is_unbound_method):
2275 return self._inject_unicode_tailmatch(
2276 node, args, is_unbound_method, 'endswith', +1)
2278 def _handle_simple_method_unicode_startswith(self, node, args, is_unbound_method):
2279 return self._inject_unicode_tailmatch(
2280 node, args, is_unbound_method, 'startswith', -1)
2282 def _inject_unicode_tailmatch(self, node, args, is_unbound_method,
2283 method_name, direction):
2284 """Replace unicode.startswith(...) and unicode.endswith(...)
2285 by a direct call to the corresponding C-API function.
2287 if len(args) not in (2,3,4):
2288 self._error_wrong_arg_count('unicode.%s' % method_name, node, args, "2-4")
2290 self._inject_int_default_argument(
2291 node, args, 2, PyrexTypes.c_py_ssize_t_type, "0")
2292 self._inject_int_default_argument(
2293 node, args, 3, PyrexTypes.c_py_ssize_t_type, "PY_SSIZE_T_MAX")
2294 args.append(ExprNodes.IntNode(
2295 node.pos, value=str(direction), type=PyrexTypes.c_int_type))
2297 method_call = self._substitute_method_call(
2298 node, "__Pyx_PyUnicode_Tailmatch", self.PyUnicode_Tailmatch_func_type,
2299 method_name, is_unbound_method, args,
2300 utility_code = unicode_tailmatch_utility_code)
2301 return method_call.coerce_to(Builtin.bool_type, self.current_env())
2303 PyUnicode_Find_func_type = PyrexTypes.CFuncType(
2304 PyrexTypes.c_py_ssize_t_type, [
2305 PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
2306 PyrexTypes.CFuncTypeArg("substring", PyrexTypes.py_object_type, None),
2307 PyrexTypes.CFuncTypeArg("start", PyrexTypes.c_py_ssize_t_type, None),
2308 PyrexTypes.CFuncTypeArg("end", PyrexTypes.c_py_ssize_t_type, None),
2309 PyrexTypes.CFuncTypeArg("direction", PyrexTypes.c_int_type, None),
2311 exception_value = '-2')
2313 def _handle_simple_method_unicode_find(self, node, args, is_unbound_method):
2314 return self._inject_unicode_find(
2315 node, args, is_unbound_method, 'find', +1)
2317 def _handle_simple_method_unicode_rfind(self, node, args, is_unbound_method):
2318 return self._inject_unicode_find(
2319 node, args, is_unbound_method, 'rfind', -1)
2321 def _inject_unicode_find(self, node, args, is_unbound_method,
2322 method_name, direction):
2323 """Replace unicode.find(...) and unicode.rfind(...) by a
2324 direct call to the corresponding C-API function.
2326 if len(args) not in (2,3,4):
2327 self._error_wrong_arg_count('unicode.%s' % method_name, node, args, "2-4")
2329 self._inject_int_default_argument(
2330 node, args, 2, PyrexTypes.c_py_ssize_t_type, "0")
2331 self._inject_int_default_argument(
2332 node, args, 3, PyrexTypes.c_py_ssize_t_type, "PY_SSIZE_T_MAX")
2333 args.append(ExprNodes.IntNode(
2334 node.pos, value=str(direction), type=PyrexTypes.c_int_type))
2336 method_call = self._substitute_method_call(
2337 node, "PyUnicode_Find", self.PyUnicode_Find_func_type,
2338 method_name, is_unbound_method, args)
2339 return method_call.coerce_to_pyobject(self.current_env())
2341 PyUnicode_Count_func_type = PyrexTypes.CFuncType(
2342 PyrexTypes.c_py_ssize_t_type, [
2343 PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
2344 PyrexTypes.CFuncTypeArg("substring", PyrexTypes.py_object_type, None),
2345 PyrexTypes.CFuncTypeArg("start", PyrexTypes.c_py_ssize_t_type, None),
2346 PyrexTypes.CFuncTypeArg("end", PyrexTypes.c_py_ssize_t_type, None),
2348 exception_value = '-1')
2350 def _handle_simple_method_unicode_count(self, node, args, is_unbound_method):
2351 """Replace unicode.count(...) by a direct call to the
2352 corresponding C-API function.
2354 if len(args) not in (2,3,4):
2355 self._error_wrong_arg_count('unicode.count', node, args, "2-4")
2357 self._inject_int_default_argument(
2358 node, args, 2, PyrexTypes.c_py_ssize_t_type, "0")
2359 self._inject_int_default_argument(
2360 node, args, 3, PyrexTypes.c_py_ssize_t_type, "PY_SSIZE_T_MAX")
2362 method_call = self._substitute_method_call(
2363 node, "PyUnicode_Count", self.PyUnicode_Count_func_type,
2364 'count', is_unbound_method, args)
2365 return method_call.coerce_to_pyobject(self.current_env())
2367 PyUnicode_Replace_func_type = PyrexTypes.CFuncType(
2368 Builtin.unicode_type, [
2369 PyrexTypes.CFuncTypeArg("str", Builtin.unicode_type, None),
2370 PyrexTypes.CFuncTypeArg("substring", PyrexTypes.py_object_type, None),
2371 PyrexTypes.CFuncTypeArg("replstr", PyrexTypes.py_object_type, None),
2372 PyrexTypes.CFuncTypeArg("maxcount", PyrexTypes.c_py_ssize_t_type, None),
2375 def _handle_simple_method_unicode_replace(self, node, args, is_unbound_method):
2376 """Replace unicode.replace(...) by a direct call to the
2377 corresponding C-API function.
2379 if len(args) not in (3,4):
2380 self._error_wrong_arg_count('unicode.replace', node, args, "3-4")
2382 self._inject_int_default_argument(
2383 node, args, 3, PyrexTypes.c_py_ssize_t_type, "-1")
2385 return self._substitute_method_call(
2386 node, "PyUnicode_Replace", self.PyUnicode_Replace_func_type,
2387 'replace', is_unbound_method, args)
2389 PyUnicode_AsEncodedString_func_type = PyrexTypes.CFuncType(
2390 Builtin.bytes_type, [
2391 PyrexTypes.CFuncTypeArg("obj", Builtin.unicode_type, None),
2392 PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_char_ptr_type, None),
2393 PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_char_ptr_type, None),
2396 PyUnicode_AsXyzString_func_type = PyrexTypes.CFuncType(
2397 Builtin.bytes_type, [
2398 PyrexTypes.CFuncTypeArg("obj", Builtin.unicode_type, None),
2401 _special_encodings = ['UTF8', 'UTF16', 'Latin1', 'ASCII',
2402 'unicode_escape', 'raw_unicode_escape']
2404 _special_codecs = [ (name, codecs.getencoder(name))
2405 for name in _special_encodings ]
2407 def _handle_simple_method_unicode_encode(self, node, args, is_unbound_method):
2408 """Replace unicode.encode(...) by a direct C-API call to the
2409 corresponding codec.
2411 if len(args) < 1 or len(args) > 3:
2412 self._error_wrong_arg_count('unicode.encode', node, args, '1-3')
2415 string_node = args[0]
2418 null_node = ExprNodes.NullNode(node.pos)
2419 return self._substitute_method_call(
2420 node, "PyUnicode_AsEncodedString",
2421 self.PyUnicode_AsEncodedString_func_type,
2422 'encode', is_unbound_method, [string_node, null_node, null_node])
2424 parameters = self._unpack_encoding_and_error_mode(node.pos, args)
2425 if parameters is None:
2427 encoding, encoding_node, error_handling, error_handling_node = parameters
2429 if isinstance(string_node, ExprNodes.UnicodeNode):
2430 # constant, so try to do the encoding at compile time
2432 value = string_node.value.encode(encoding, error_handling)
2434 # well, looks like we can't
2437 value = BytesLiteral(value)
2438 value.encoding = encoding
2439 return ExprNodes.BytesNode(
2440 string_node.pos, value=value, type=Builtin.bytes_type)
2442 if error_handling == 'strict':
2443 # try to find a specific encoder function
2444 codec_name = self._find_special_codec_name(encoding)
2445 if codec_name is not None:
2446 encode_function = "PyUnicode_As%sString" % codec_name
2447 return self._substitute_method_call(
2448 node, encode_function,
2449 self.PyUnicode_AsXyzString_func_type,
2450 'encode', is_unbound_method, [string_node])
2452 return self._substitute_method_call(
2453 node, "PyUnicode_AsEncodedString",
2454 self.PyUnicode_AsEncodedString_func_type,
2455 'encode', is_unbound_method,
2456 [string_node, encoding_node, error_handling_node])
2458 PyUnicode_DecodeXyz_func_type = PyrexTypes.CFuncType(
2459 Builtin.unicode_type, [
2460 PyrexTypes.CFuncTypeArg("string", PyrexTypes.c_char_ptr_type, None),
2461 PyrexTypes.CFuncTypeArg("size", PyrexTypes.c_py_ssize_t_type, None),
2462 PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_char_ptr_type, None),
2465 PyUnicode_Decode_func_type = PyrexTypes.CFuncType(
2466 Builtin.unicode_type, [
2467 PyrexTypes.CFuncTypeArg("string", PyrexTypes.c_char_ptr_type, None),
2468 PyrexTypes.CFuncTypeArg("size", PyrexTypes.c_py_ssize_t_type, None),
2469 PyrexTypes.CFuncTypeArg("encoding", PyrexTypes.c_char_ptr_type, None),
2470 PyrexTypes.CFuncTypeArg("errors", PyrexTypes.c_char_ptr_type, None),
2473 def _handle_simple_method_bytes_decode(self, node, args, is_unbound_method):
2474 """Replace char*.decode() by a direct C-API call to the
2475 corresponding codec, possibly resoving a slice on the char*.
2477 if len(args) < 1 or len(args) > 3:
2478 self._error_wrong_arg_count('bytes.decode', node, args, '1-3')
2481 if isinstance(args[0], ExprNodes.SliceIndexNode):
2482 index_node = args[0]
2483 string_node = index_node.base
2484 if not string_node.type.is_string:
2485 # nothing to optimise here
2487 start, stop = index_node.start, index_node.stop
2488 if not start or start.constant_result == 0:
2491 if start.type.is_pyobject:
2492 start = start.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_env())
2494 start = UtilNodes.LetRefNode(start)
2496 string_node = ExprNodes.AddNode(pos=start.pos,
2497 operand1=string_node,
2501 type=string_node.type
2503 if stop and stop.type.is_pyobject:
2504 stop = stop.coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_env())
2505 elif isinstance(args[0], ExprNodes.CoerceToPyTypeNode) \
2506 and args[0].arg.type.is_string:
2507 # use strlen() to find the string length, just as CPython would
2509 string_node = args[0].arg
2511 # let Python do its job
2515 if start or not string_node.is_name:
2516 string_node = UtilNodes.LetRefNode(string_node)
2517 temps.append(string_node)
2518 stop = ExprNodes.PythonCapiCallNode(
2519 string_node.pos, "strlen", self.Pyx_strlen_func_type,
2520 args = [string_node],
2522 utility_code = include_string_h_utility_code,
2523 ).coerce_to(PyrexTypes.c_py_ssize_t_type, self.current_env())
2525 stop = ExprNodes.SubNode(
2531 type = PyrexTypes.c_py_ssize_t_type
2534 parameters = self._unpack_encoding_and_error_mode(node.pos, args)
2535 if parameters is None:
2537 encoding, encoding_node, error_handling, error_handling_node = parameters
2539 # try to find a specific encoder function
2541 if encoding is not None:
2542 codec_name = self._find_special_codec_name(encoding)
2543 if codec_name is not None:
2544 decode_function = "PyUnicode_Decode%s" % codec_name
2545 node = ExprNodes.PythonCapiCallNode(
2546 node.pos, decode_function,
2547 self.PyUnicode_DecodeXyz_func_type,
2548 args = [string_node, stop, error_handling_node],
2549 is_temp = node.is_temp,
2552 node = ExprNodes.PythonCapiCallNode(
2553 node.pos, "PyUnicode_Decode",
2554 self.PyUnicode_Decode_func_type,
2555 args = [string_node, stop, encoding_node, error_handling_node],
2556 is_temp = node.is_temp,
2559 for temp in temps[::-1]:
2560 node = UtilNodes.EvalWithTempExprNode(temp, node)
2563 def _find_special_codec_name(self, encoding):
2565 requested_codec = codecs.getencoder(encoding)
2568 for name, codec in self._special_codecs:
2569 if codec == requested_codec:
2571 name = ''.join([ s.capitalize()
2572 for s in name.split('_')])
2576 def _unpack_encoding_and_error_mode(self, pos, args):
2577 null_node = ExprNodes.NullNode(pos)
2580 encoding_node = args[1]
2581 if isinstance(encoding_node, ExprNodes.CoerceToPyTypeNode):
2582 encoding_node = encoding_node.arg
2583 if isinstance(encoding_node, (ExprNodes.UnicodeNode, ExprNodes.StringNode,
2584 ExprNodes.BytesNode)):
2585 encoding = encoding_node.value
2586 encoding_node = ExprNodes.BytesNode(encoding_node.pos, value=encoding,
2587 type=PyrexTypes.c_char_ptr_type)
2588 elif encoding_node.type is Builtin.bytes_type:
2590 encoding_node = encoding_node.coerce_to(
2591 PyrexTypes.c_char_ptr_type, self.current_env())
2592 elif encoding_node.type.is_string:
2598 encoding_node = null_node
2601 error_handling_node = args[2]
2602 if isinstance(error_handling_node, ExprNodes.CoerceToPyTypeNode):
2603 error_handling_node = error_handling_node.arg
2604 if isinstance(error_handling_node,
2605 (ExprNodes.UnicodeNode, ExprNodes.StringNode,
2606 ExprNodes.BytesNode)):
2607 error_handling = error_handling_node.value
2608 if error_handling == 'strict':
2609 error_handling_node = null_node
2611 error_handling_node = ExprNodes.BytesNode(
2612 error_handling_node.pos, value=error_handling,
2613 type=PyrexTypes.c_char_ptr_type)
2614 elif error_handling_node.type is Builtin.bytes_type:
2615 error_handling = None
2616 error_handling_node = error_handling_node.coerce_to(
2617 PyrexTypes.c_char_ptr_type, self.current_env())
2618 elif error_handling_node.type.is_string:
2619 error_handling = None
2623 error_handling = 'strict'
2624 error_handling_node = null_node
2626 return (encoding, encoding_node, error_handling, error_handling_node)
2631 def _substitute_method_call(self, node, name, func_type,
2632 attr_name, is_unbound_method, args=(),
2634 may_return_none=ExprNodes.PythonCapiCallNode.may_return_none):
2636 if args and not args[0].is_literal:
2638 if is_unbound_method:
2639 self_arg = self_arg.as_none_safe_node(
2640 "descriptor '%s' requires a '%s' object but received a 'NoneType'" % (
2641 attr_name, node.function.obj.name))
2643 self_arg = self_arg.as_none_safe_node(
2644 "'NoneType' object has no attribute '%s'" % attr_name,
2645 error = "PyExc_AttributeError")
2647 return ExprNodes.PythonCapiCallNode(
2648 node.pos, name, func_type,
2650 is_temp = node.is_temp,
2651 utility_code = utility_code,
2652 may_return_none = may_return_none,
2655 def _inject_int_default_argument(self, node, args, arg_index, type, default_value):
2656 assert len(args) >= arg_index
2657 if len(args) == arg_index:
2658 args.append(ExprNodes.IntNode(node.pos, value=str(default_value),
2659 type=type, constant_result=default_value))
2661 args[arg_index] = args[arg_index].coerce_to(type, self.current_env())
2663 def _inject_bint_default_argument(self, node, args, arg_index, default_value):
2664 assert len(args) >= arg_index
2665 if len(args) == arg_index:
2666 default_value = bool(default_value)
2667 args.append(ExprNodes.BoolNode(node.pos, value=default_value,
2668 constant_result=default_value))
2670 args[arg_index] = args[arg_index].coerce_to_boolean(self.current_env())
2673 py_unicode_istitle_utility_code = UtilityCode(
2674 # Py_UNICODE_ISTITLE() doesn't match unicode.istitle() as the latter
2675 # additionally allows character that comply with Py_UNICODE_ISUPPER()
2677 static CYTHON_INLINE int __Pyx_Py_UNICODE_ISTITLE(Py_UNICODE uchar); /* proto */
2680 static CYTHON_INLINE int __Pyx_Py_UNICODE_ISTITLE(Py_UNICODE uchar) {
2681 return Py_UNICODE_ISTITLE(uchar) || Py_UNICODE_ISUPPER(uchar);
2685 unicode_tailmatch_utility_code = UtilityCode(
2686 # Python's unicode.startswith() and unicode.endswith() support a
2687 # tuple of prefixes/suffixes, whereas it's much more common to
2688 # test for a single unicode string.
2690 static int __Pyx_PyUnicode_Tailmatch(PyObject* s, PyObject* substr, \
2691 Py_ssize_t start, Py_ssize_t end, int direction);
2694 static int __Pyx_PyUnicode_Tailmatch(PyObject* s, PyObject* substr,
2695 Py_ssize_t start, Py_ssize_t end, int direction) {
2696 if (unlikely(PyTuple_Check(substr))) {
2699 for (i = 0; i < PyTuple_GET_SIZE(substr); i++) {
2700 result = PyUnicode_Tailmatch(s, PyTuple_GET_ITEM(substr, i),
2701 start, end, direction);
2708 return PyUnicode_Tailmatch(s, substr, start, end, direction);
2713 dict_getitem_default_utility_code = UtilityCode(
2715 static PyObject* __Pyx_PyDict_GetItemDefault(PyObject* d, PyObject* key, PyObject* default_value) {
2717 #if PY_MAJOR_VERSION >= 3
2718 value = PyDict_GetItemWithError(d, key);
2719 if (unlikely(!value)) {
2720 if (unlikely(PyErr_Occurred()))
2722 value = default_value;
2726 if (PyString_CheckExact(key) || PyUnicode_CheckExact(key) || PyInt_CheckExact(key)) {
2727 /* these presumably have safe hash functions */
2728 value = PyDict_GetItem(d, key);
2729 if (unlikely(!value)) {
2730 value = default_value;
2735 m = __Pyx_GetAttrString(d, "get");
2736 if (!m) return NULL;
2737 value = PyObject_CallFunctionObjArgs(m, key,
2738 (default_value == Py_None) ? NULL : default_value, NULL);
2748 append_utility_code = UtilityCode(
2750 static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
2751 if (likely(PyList_CheckExact(L))) {
2752 if (PyList_Append(L, x) < 0) return NULL;
2754 return Py_None; /* this is just to have an accurate signature */
2758 m = __Pyx_GetAttrString(L, "append");
2759 if (!m) return NULL;
2760 r = PyObject_CallFunctionObjArgs(m, x, NULL);
2770 pop_utility_code = UtilityCode(
2772 static CYTHON_INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L) {
2774 #if PY_VERSION_HEX >= 0x02040000
2775 if (likely(PyList_CheckExact(L))
2776 /* Check that both the size is positive and no reallocation shrinking needs to be done. */
2777 && likely(PyList_GET_SIZE(L) > (((PyListObject*)L)->allocated >> 1))) {
2779 return PyList_GET_ITEM(L, PyList_GET_SIZE(L));
2782 m = __Pyx_GetAttrString(L, "pop");
2783 if (!m) return NULL;
2784 r = PyObject_CallObject(m, NULL);
2792 pop_index_utility_code = UtilityCode(
2794 static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix);
2797 static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix) {
2798 PyObject *r, *m, *t, *py_ix;
2799 #if PY_VERSION_HEX >= 0x02040000
2800 if (likely(PyList_CheckExact(L))) {
2801 Py_ssize_t size = PyList_GET_SIZE(L);
2802 if (likely(size > (((PyListObject*)L)->allocated >> 1))) {
2806 if (likely(0 <= ix && ix < size)) {
2808 PyObject* v = PyList_GET_ITEM(L, ix);
2811 for(i=ix; i<size; i++) {
2812 PyList_SET_ITEM(L, i, PyList_GET_ITEM(L, i+1));
2820 m = __Pyx_GetAttrString(L, "pop");
2822 py_ix = PyInt_FromSsize_t(ix);
2823 if (!py_ix) goto bad;
2826 PyTuple_SET_ITEM(t, 0, py_ix);
2828 r = PyObject_CallObject(m, t);
2842 pyobject_as_double_utility_code = UtilityCode(
2844 static double __Pyx__PyObject_AsDouble(PyObject* obj); /* proto */
2846 #define __Pyx_PyObject_AsDouble(obj) \\
2847 ((likely(PyFloat_CheckExact(obj))) ? \\
2848 PyFloat_AS_DOUBLE(obj) : __Pyx__PyObject_AsDouble(obj))
2851 static double __Pyx__PyObject_AsDouble(PyObject* obj) {
2852 PyObject* float_value;
2853 if (Py_TYPE(obj)->tp_as_number && Py_TYPE(obj)->tp_as_number->nb_float) {
2854 return PyFloat_AsDouble(obj);
2855 } else if (PyUnicode_CheckExact(obj) || PyBytes_CheckExact(obj)) {
2856 #if PY_MAJOR_VERSION >= 3
2857 float_value = PyFloat_FromString(obj);
2859 float_value = PyFloat_FromString(obj, 0);
2862 PyObject* args = PyTuple_New(1);
2863 if (unlikely(!args)) goto bad;
2864 PyTuple_SET_ITEM(args, 0, obj);
2865 float_value = PyObject_Call((PyObject*)&PyFloat_Type, args, 0);
2866 PyTuple_SET_ITEM(args, 0, 0);
2869 if (likely(float_value)) {
2870 double value = PyFloat_AS_DOUBLE(float_value);
2871 Py_DECREF(float_value);
2881 bytes_index_utility_code = UtilityCode(
2883 static CYTHON_INLINE char __Pyx_PyBytes_GetItemInt(PyObject* unicode, Py_ssize_t index, int check_bounds); /* proto */
2886 static CYTHON_INLINE char __Pyx_PyBytes_GetItemInt(PyObject* bytes, Py_ssize_t index, int check_bounds) {
2888 if (unlikely(index >= PyBytes_GET_SIZE(bytes)) |
2889 ((index < 0) & unlikely(index < -PyBytes_GET_SIZE(bytes)))) {
2890 PyErr_Format(PyExc_IndexError, "string index out of range");
2895 index += PyBytes_GET_SIZE(bytes);
2896 return PyBytes_AS_STRING(bytes)[index];
2902 include_string_h_utility_code = UtilityCode(
2909 tpnew_utility_code = UtilityCode(
2911 static CYTHON_INLINE PyObject* __Pyx_tp_new(PyObject* type_obj) {
2912 return (PyObject*) (((PyTypeObject*)(type_obj))->tp_new(
2913 (PyTypeObject*)(type_obj), %(TUPLE)s, NULL));
2915 """ % {'TUPLE' : Naming.empty_tuple}
2919 class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
2920 """Calculate the result of constant expressions to store it in
2921 ``expr_node.constant_result``, and replace trivial cases by their
2924 def _calculate_const(self, node):
2925 if node.constant_result is not ExprNodes.constant_value_not_set:
2928 # make sure we always set the value
2929 not_a_constant = ExprNodes.not_a_constant
2930 node.constant_result = not_a_constant
2932 # check if all children are constant
2933 children = self.visitchildren(node)
2934 for child_result in children.itervalues():
2935 if type(child_result) is list:
2936 for child in child_result:
2937 if getattr(child, 'constant_result', not_a_constant) is not_a_constant:
2939 elif getattr(child_result, 'constant_result', not_a_constant) is not_a_constant:
2942 # now try to calculate the real constant value
2944 node.calculate_constant_result()
2945 # if node.constant_result is not ExprNodes.not_a_constant:
2946 # print node.__class__.__name__, node.constant_result
2947 except (ValueError, TypeError, KeyError, IndexError, AttributeError, ArithmeticError):
2948 # ignore all 'normal' errors here => no constant result
2951 # this looks like a real error
2952 import traceback, sys
2953 traceback.print_exc(file=sys.stdout)
2955 NODE_TYPE_ORDER = (ExprNodes.CharNode, ExprNodes.IntNode,
2956 ExprNodes.LongNode, ExprNodes.FloatNode)
2958 def _widest_node_class(self, *nodes):
2960 return self.NODE_TYPE_ORDER[
2961 max(map(self.NODE_TYPE_ORDER.index, map(type, nodes)))]
2965 def visit_ExprNode(self, node):
2966 self._calculate_const(node)
2969 def visit_BoolBinopNode(self, node):
2970 self._calculate_const(node)
2971 if node.constant_result is ExprNodes.not_a_constant:
2973 if not node.operand1.is_literal or not node.operand2.is_literal:
2974 # We calculate other constants to make them available to
2975 # the compiler, but we only aggregate constant nodes
2976 # recursively, so non-const nodes are straight out.
2979 if node.constant_result == node.operand1.constant_result and node.operand1.is_literal:
2980 return node.operand1
2981 elif node.constant_result == node.operand2.constant_result and node.operand2.is_literal:
2982 return node.operand2
2984 # FIXME: we could do more ...
2987 def visit_BinopNode(self, node):
2988 self._calculate_const(node)
2989 if node.constant_result is ExprNodes.not_a_constant:
2991 if isinstance(node.constant_result, float):
2992 # We calculate float constants to make them available to
2993 # the compiler, but we do not aggregate them into a
2994 # constant node to prevent any loss of precision.
2996 if not node.operand1.is_literal or not node.operand2.is_literal:
2997 # We calculate other constants to make them available to
2998 # the compiler, but we only aggregate constant nodes
2999 # recursively, so non-const nodes are straight out.
3002 # now inject a new constant node with the calculated value
3004 type1, type2 = node.operand1.type, node.operand2.type
3005 if type1 is None or type2 is None:
3007 except AttributeError:
3011 new_node = node.operand1
3013 widest_type = PyrexTypes.widest_numeric_type(type1, type2)
3014 if type(node.operand1) is type(node.operand2):
3015 new_node = node.operand1
3016 new_node.type = widest_type
3017 elif type1 is widest_type:
3018 new_node = node.operand1
3019 elif type2 is widest_type:
3020 new_node = node.operand2
3022 target_class = self._widest_node_class(
3023 node.operand1, node.operand2)
3024 if target_class is None:
3026 new_node = target_class(pos=node.pos, type = widest_type)
3028 new_node.constant_result = node.constant_result
3029 if isinstance(node, ExprNodes.BoolNode):
3030 new_node.value = node.constant_result
3032 new_node.value = str(node.constant_result)
3033 #new_node = new_node.coerce_to(node.type, self.current_scope)
3036 def visit_PrimaryCmpNode(self, node):
3037 self._calculate_const(node)
3038 if node.constant_result is ExprNodes.not_a_constant:
3040 bool_result = bool(node.constant_result)
3041 return ExprNodes.BoolNode(node.pos, value=bool_result,
3042 constant_result=bool_result)
3044 def visit_IfStatNode(self, node):
3045 self.visitchildren(node)
3046 # eliminate dead code based on constant condition results
3048 for if_clause in node.if_clauses:
3049 condition_result = if_clause.get_constant_condition_result()
3050 if condition_result is None:
3051 # unknown result => normal runtime evaluation
3052 if_clauses.append(if_clause)
3053 elif condition_result == True:
3054 # subsequent clauses can safely be dropped
3055 node.else_clause = if_clause.body
3058 assert condition_result == False
3060 return node.else_clause
3061 node.if_clauses = if_clauses
3064 # in the future, other nodes can have their own handler method here
3065 # that can replace them with a constant result node
3067 visit_Node = Visitor.VisitorTransform.recurse_to_children
3070 class FinalOptimizePhase(Visitor.CythonTransform):
3072 This visitor handles several commuting optimizations, and is run
3073 just before the C code generation phase.
3075 The optimizations currently implemented in this class are:
3076 - eliminate None assignment and refcounting for first assignment.
3077 - isinstance -> typecheck for cdef types
3078 - eliminate checks for None and/or types that became redundant after tree changes
3080 def visit_SingleAssignmentNode(self, node):
3081 """Avoid redundant initialisation of local variables before their
3084 self.visitchildren(node)
3087 lhs.lhs_of_first_assignment = True
3088 if isinstance(lhs, ExprNodes.NameNode) and lhs.entry.type.is_pyobject:
3089 # Have variable initialized to 0 rather than None
3090 lhs.entry.init_to_none = False
3094 def visit_SimpleCallNode(self, node):
3095 """Replace generic calls to isinstance(x, type) by a more efficient
3098 self.visitchildren(node)
3099 if node.function.type.is_cfunction and isinstance(node.function, ExprNodes.NameNode):
3100 if node.function.name == 'isinstance':
3101 type_arg = node.args[1]
3102 if type_arg.type.is_builtin_type and type_arg.type.name == 'type':
3103 from CythonScope import utility_scope
3104 node.function.entry = utility_scope.lookup('PyObject_TypeCheck')
3105 node.function.type = node.function.entry.type
3106 PyTypeObjectPtr = PyrexTypes.CPtrType(utility_scope.lookup('PyTypeObject').type)
3107 node.args[1] = ExprNodes.CastNode(node.args[1], PyTypeObjectPtr)
3110 def visit_PyTypeTestNode(self, node):
3111 """Remove tests for alternatively allowed None values from
3112 type tests when we know that the argument cannot be None
3115 self.visitchildren(node)
3116 if not node.notnone:
3117 if not node.arg.may_be_none():