Cython has moved to github.

cython-devel

view Cython/Compiler/ExprNodes.py @ 2194:b9d8cecc8975

general optimisation support for calls to builtin types and their methods

currently providing optimisations for
- getattr(o,a)
- getattr(o,a,d)
- X.append(o)
- L.append(o)
- list.append(L,x)
author Stefan Behnel <scoder@users.berlios.de>
date Sun Mar 29 13:27:55 2009 +0200 (3 years ago)
parents 2f3176c9ae7f
children 222e9c9a8967
line source
1 #
2 # Pyrex - Parse tree nodes for expressions
3 #
5 import operator
7 from Errors import error, warning, InternalError
8 from Errors import hold_errors, release_errors, held_errors, report_error
9 from Cython.Utils import UtilityCode
10 import StringEncoding
11 import Naming
12 from Nodes import Node
13 import PyrexTypes
14 from PyrexTypes import py_object_type, c_long_type, typecast, error_type
15 from Builtin import list_type, tuple_type, set_type, dict_type, unicode_type
16 import Builtin
17 import Symtab
18 import Options
19 from Annotate import AnnotationItem
21 from Cython.Debugging import print_call_chain
22 from DebugFlags import debug_disposal_code, debug_temp_alloc, \
23 debug_coercion
25 try:
26 set
27 except NameError:
28 from sets import Set as set
30 class NotConstant(object): pass # just for the name
31 not_a_constant = NotConstant()
32 constant_value_not_set = object()
34 class ExprNode(Node):
35 # subexprs [string] Class var holding names of subexpr node attrs
36 # type PyrexType Type of the result
37 # result_code string Code fragment
38 # result_ctype string C type of result_code if different from type
39 # is_temp boolean Result is in a temporary variable
40 # is_sequence_constructor
41 # boolean Is a list or tuple constructor expression
42 # saved_subexpr_nodes
43 # [ExprNode or [ExprNode or None] or None]
44 # Cached result of subexpr_nodes()
46 result_ctype = None
47 type = None
49 # The Analyse Expressions phase for expressions is split
50 # into two sub-phases:
51 #
52 # Analyse Types
53 # Determines the result type of the expression based
54 # on the types of its sub-expressions, and inserts
55 # coercion nodes into the expression tree where needed.
56 # Marks nodes which will need to have temporary variables
57 # allocated.
58 #
59 # Allocate Temps
60 # Allocates temporary variables where needed, and fills
61 # in the result_code field of each node.
62 #
63 # ExprNode provides some convenience routines which
64 # perform both of the above phases. These should only
65 # be called from statement nodes, and only when no
66 # coercion nodes need to be added around the expression
67 # being analysed. In that case, the above two phases
68 # should be invoked separately.
69 #
70 # Framework code in ExprNode provides much of the common
71 # processing for the various phases. It makes use of the
72 # 'subexprs' class attribute of ExprNodes, which should
73 # contain a list of the names of attributes which can
74 # hold sub-nodes or sequences of sub-nodes.
75 #
76 # The framework makes use of a number of abstract methods.
77 # Their responsibilities are as follows.
78 #
79 # Declaration Analysis phase
80 #
81 # analyse_target_declaration
82 # Called during the Analyse Declarations phase to analyse
83 # the LHS of an assignment or argument of a del statement.
84 # Nodes which cannot be the LHS of an assignment need not
85 # implement it.
86 #
87 # Expression Analysis phase
88 #
89 # analyse_types
90 # - Call analyse_types on all sub-expressions.
91 # - Check operand types, and wrap coercion nodes around
92 # sub-expressions where needed.
93 # - Set the type of this node.
94 # - If a temporary variable will be required for the
95 # result, set the is_temp flag of this node.
96 #
97 # analyse_target_types
98 # Called during the Analyse Types phase to analyse
99 # the LHS of an assignment or argument of a del
100 # statement. Similar responsibilities to analyse_types.
101 #
102 # allocate_temps
103 # - Call allocate_temps for all sub-nodes.
104 # - Call allocate_temp for this node.
105 # - If a temporary was allocated, call release_temp on
106 # all sub-expressions.
107 #
108 # allocate_target_temps
109 # - Call allocate_temps on sub-nodes and allocate any other
110 # temps used during assignment.
111 # - Fill in result_code with a C lvalue if needed.
112 # - If a rhs node is supplied, call release_temp on it.
113 # - Call release_temp on sub-nodes and release any other
114 # temps used during assignment.
115 #
116 # target_code
117 # Called by the default implementation of allocate_target_temps.
118 # Should return a C lvalue for assigning to the node. The default
119 # implementation calls calculate_result_code.
120 #
121 # check_const
122 # - Check that this node and its subnodes form a
123 # legal constant expression. If so, do nothing,
124 # otherwise call not_const.
125 #
126 # The default implementation of check_const
127 # assumes that the expression is not constant.
128 #
129 # check_const_addr
130 # - Same as check_const, except check that the
131 # expression is a C lvalue whose address is
132 # constant. Otherwise, call addr_not_const.
133 #
134 # The default implementation of calc_const_addr
135 # assumes that the expression is not a constant
136 # lvalue.
137 #
138 # Code Generation phase
139 #
140 # generate_evaluation_code
141 # - Call generate_evaluation_code for sub-expressions.
142 # - Perform the functions of generate_result_code
143 # (see below).
144 # - If result is temporary, call generate_disposal_code
145 # on all sub-expressions.
146 #
147 # A default implementation of generate_evaluation_code
148 # is provided which uses the following abstract methods:
149 #
150 # generate_result_code
151 # - Generate any C statements necessary to calculate
152 # the result of this node from the results of its
153 # sub-expressions.
154 #
155 # calculate_result_code
156 # - Should return a C code fragment evaluating to the
157 # result. This is only called when the result is not
158 # a temporary.
159 #
160 # generate_assignment_code
161 # Called on the LHS of an assignment.
162 # - Call generate_evaluation_code for sub-expressions.
163 # - Generate code to perform the assignment.
164 # - If the assignment absorbed a reference, call
165 # generate_post_assignment_code on the RHS,
166 # otherwise call generate_disposal_code on it.
167 #
168 # generate_deletion_code
169 # Called on an argument of a del statement.
170 # - Call generate_evaluation_code for sub-expressions.
171 # - Generate code to perform the deletion.
172 # - Call generate_disposal_code on all sub-expressions.
173 #
174 #
176 is_sequence_constructor = 0
177 is_attribute = 0
179 saved_subexpr_nodes = None
180 is_temp = 0
181 is_target = 0
183 constant_result = constant_value_not_set
185 try:
186 _get_child_attrs = operator.attrgetter('subexprs')
187 except AttributeError:
188 # Python 2.3
189 def _get_child_attrs(self):
190 return self.subexprs
191 child_attrs = property(fget=_get_child_attrs)
193 def not_implemented(self, method_name):
194 print_call_chain(method_name, "not implemented") ###
195 raise InternalError(
196 "%s.%s not implemented" %
197 (self.__class__.__name__, method_name))
199 def is_lvalue(self):
200 return 0
202 def is_ephemeral(self):
203 # An ephemeral node is one whose result is in
204 # a Python temporary and we suspect there are no
205 # other references to it. Certain operations are
206 # disallowed on such values, since they are
207 # likely to result in a dangling pointer.
208 return self.type.is_pyobject and self.is_temp
210 def subexpr_nodes(self):
211 # Extract a list of subexpression nodes based
212 # on the contents of the subexprs class attribute.
213 nodes = []
214 for name in self.subexprs:
215 item = getattr(self, name)
216 if item is not None:
217 if type(item) is list:
218 nodes.extend(item)
219 else:
220 nodes.append(item)
221 return nodes
223 def result(self):
224 if not self.is_temp or self.is_target:
225 return self.calculate_result_code()
226 else: # i.e. self.is_temp:
227 return self.result_code
229 def result_as(self, type = None):
230 # Return the result code cast to the specified C type.
231 return typecast(type, self.ctype(), self.result())
233 def py_result(self):
234 # Return the result code cast to PyObject *.
235 return self.result_as(py_object_type)
237 def ctype(self):
238 # Return the native C type of the result (i.e. the
239 # C type of the result_code expression).
240 return self.result_ctype or self.type
242 def get_constant_result_code(self):
243 # Return the constant value of this node as a result code
244 # string, or None if the node is not constant.
245 return None
247 def calculate_constant_result(self):
248 # Calculate the constant result of this expression and store
249 # it in ``self.constant_result``. Does nothing by default,
250 # thus leaving ``self.constant_result`` unknown.
251 #
252 # This must only be called when it is assured that all
253 # sub-expressions have a valid constant_result value. The
254 # ConstantFolding transform will do this.
255 pass
257 def compile_time_value(self, denv):
258 # Return value of compile-time expression, or report error.
259 error(self.pos, "Invalid compile-time expression")
261 def compile_time_value_error(self, e):
262 error(self.pos, "Error in compile-time expression: %s: %s" % (
263 e.__class__.__name__, e))
265 # ------------- Declaration Analysis ----------------
267 def analyse_target_declaration(self, env):
268 error(self.pos, "Cannot assign to or delete this")
270 # ------------- Expression Analysis ----------------
272 def analyse_const_expression(self, env):
273 # Called during the analyse_declarations phase of a
274 # constant expression. Analyses the expression's type,
275 # checks whether it is a legal const expression,
276 # and determines its value.
277 self.analyse_types(env)
278 self.allocate_temps(env)
279 self.check_const()
281 def analyse_expressions(self, env):
282 # Convenience routine performing both the Type
283 # Analysis and Temp Allocation phases for a whole
284 # expression.
285 self.analyse_types(env)
286 self.allocate_temps(env)
288 def analyse_target_expression(self, env, rhs):
289 # Convenience routine performing both the Type
290 # Analysis and Temp Allocation phases for the LHS of
291 # an assignment.
292 self.analyse_target_types(env)
293 self.allocate_target_temps(env, rhs)
295 def analyse_boolean_expression(self, env):
296 # Analyse expression and coerce to a boolean.
297 self.analyse_types(env)
298 bool = self.coerce_to_boolean(env)
299 bool.allocate_temps(env)
300 return bool
302 def analyse_temp_boolean_expression(self, env):
303 # Analyse boolean expression and coerce result into
304 # a temporary. This is used when a branch is to be
305 # performed on the result and we won't have an
306 # opportunity to ensure disposal code is executed
307 # afterwards. By forcing the result into a temporary,
308 # we ensure that all disposal has been done by the
309 # time we get the result.
310 self.analyse_types(env)
311 bool = self.coerce_to_boolean(env)
312 temp_bool = bool.coerce_to_temp(env)
313 temp_bool.allocate_temps(env)
314 return temp_bool
316 # --------------- Type Analysis ------------------
318 def analyse_as_module(self, env):
319 # If this node can be interpreted as a reference to a
320 # cimported module, return its scope, else None.
321 return None
323 def analyse_as_type(self, env):
324 # If this node can be interpreted as a reference to a
325 # type, return that type, else None.
326 return None
328 def analyse_as_extension_type(self, env):
329 # If this node can be interpreted as a reference to an
330 # extension type, return its type, else None.
331 return None
333 def analyse_types(self, env):
334 self.not_implemented("analyse_types")
336 def analyse_target_types(self, env):
337 self.analyse_types(env)
339 def gil_check(self, env):
340 # By default, any expression based on Python objects is
341 # prevented in nogil environments. Subtypes must override
342 # this if they can work without the GIL.
343 if self.type.is_pyobject:
344 self._gil_check(env)
346 def gil_assignment_check(self, env):
347 if env.nogil and self.type.is_pyobject:
348 error(self.pos, "Assignment of Python object not allowed without gil")
350 def check_const(self):
351 self.not_const()
353 def not_const(self):
354 error(self.pos, "Not allowed in a constant expression")
356 def check_const_addr(self):
357 self.addr_not_const()
359 def addr_not_const(self):
360 error(self.pos, "Address is not constant")
362 # ----------------- Result Allocation -----------------
364 def result_in_temp(self):
365 # Return true if result is in a temporary owned by
366 # this node or one of its subexpressions. Overridden
367 # by certain nodes which can share the result of
368 # a subnode.
369 return self.is_temp
371 def allocate_target_temps(self, env, rhs):
372 # Perform temp allocation for the LHS of an assignment.
373 if debug_temp_alloc:
374 print("%s Allocating target temps" % self)
375 self.allocate_subexpr_temps(env)
376 self.is_target = True
377 if rhs:
378 rhs.release_temp(env)
379 self.release_subexpr_temps(env)
381 def allocate_temps(self, env, result = None):
382 # Allocate temporary variables for this node and
383 # all its sub-expressions. If a result is specified,
384 # this must be a temp node and the specified variable
385 # is used as the result instead of allocating a new
386 # one.
387 if debug_temp_alloc:
388 print("%s Allocating temps" % self)
389 self.allocate_subexpr_temps(env)
390 self.allocate_temp(env, result)
391 if self.is_temp:
392 self.release_subexpr_temps(env)
394 def allocate_subexpr_temps(self, env):
395 # Allocate temporary variables for all sub-expressions
396 # of this node.
397 if debug_temp_alloc:
398 print("%s Allocating temps for: %s" % (self, self.subexprs))
399 for node in self.subexpr_nodes():
400 if node:
401 if debug_temp_alloc:
402 print("%s Allocating temps for %s" % (self, node))
403 node.allocate_temps(env)
405 def allocate_temp(self, env, result = None):
406 # If this node requires a temporary variable for its
407 # result, allocate one, otherwise set the result to
408 # a C code fragment. If a result is specified,
409 # this must be a temp node and the specified variable
410 # is used as the result instead of allocating a new
411 # one.
412 if debug_temp_alloc:
413 print("%s Allocating temp" % self)
414 if result:
415 if not self.is_temp:
416 raise InternalError("Result forced on non-temp node")
417 self.result_code = result
418 elif self.is_temp:
419 type = self.type
420 if not type.is_void:
421 if type.is_pyobject:
422 type = PyrexTypes.py_object_type
423 self.result_code = env.allocate_temp(type)
424 else:
425 self.result_code = None
426 if debug_temp_alloc:
427 print("%s Allocated result %s" % (self, self.result_code))
429 def target_code(self):
430 # Return code fragment for use as LHS of a C assignment.
431 return self.calculate_result_code()
433 def calculate_result_code(self):
434 self.not_implemented("calculate_result_code")
436 # def release_target_temp(self, env):
437 # # Release temporaries used by LHS of an assignment.
438 # self.release_subexpr_temps(env)
440 def release_temp(self, env):
441 # If this node owns a temporary result, release it,
442 # otherwise release results of its sub-expressions.
443 if self.is_temp:
444 if debug_temp_alloc:
445 print("%s Releasing result %s" % (self, self.result_code))
446 env.release_temp(self.result_code)
447 else:
448 self.release_subexpr_temps(env)
450 def release_subexpr_temps(self, env):
451 # Release the results of all sub-expressions of
452 # this node.
453 for node in self.subexpr_nodes():
454 if node:
455 node.release_temp(env)
457 # ---------------- Code Generation -----------------
459 def make_owned_reference(self, code):
460 # If result is a pyobject, make sure we own
461 # a reference to it.
462 if self.type.is_pyobject and not self.result_in_temp():
463 code.put_incref(self.result(), self.ctype())
465 def generate_evaluation_code(self, code):
466 code.mark_pos(self.pos)
467 # Generate code to evaluate this node and
468 # its sub-expressions, and dispose of any
469 # temporary results of its sub-expressions.
470 self.generate_subexpr_evaluation_code(code)
471 self.generate_result_code(code)
472 if self.is_temp:
473 self.generate_subexpr_disposal_code(code)
474 self.free_subexpr_temps(code)
476 def generate_subexpr_evaluation_code(self, code):
477 for node in self.subexpr_nodes():
478 node.generate_evaluation_code(code)
480 def generate_result_code(self, code):
481 self.not_implemented("generate_result_code")
483 def generate_disposal_code(self, code):
484 # If necessary, generate code to dispose of
485 # temporary Python reference.
486 if self.is_temp:
487 if self.type.is_pyobject:
488 code.put_decref_clear(self.result(), self.ctype())
489 else:
490 self.generate_subexpr_disposal_code(code)
492 def generate_subexpr_disposal_code(self, code):
493 # Generate code to dispose of temporary results
494 # of all sub-expressions.
495 for node in self.subexpr_nodes():
496 node.generate_disposal_code(code)
498 def generate_post_assignment_code(self, code):
499 # Same as generate_disposal_code except that
500 # assignment will have absorbed a reference to
501 # the result if it is a Python object.
502 if self.is_temp:
503 if self.type.is_pyobject:
504 code.putln("%s = 0;" % self.result())
505 else:
506 self.generate_subexpr_disposal_code(code)
508 def generate_assignment_code(self, rhs, code):
509 # Stub method for nodes which are not legal as
510 # the LHS of an assignment. An error will have
511 # been reported earlier.
512 pass
514 def generate_deletion_code(self, code):
515 # Stub method for nodes that are not legal as
516 # the argument of a del statement. An error
517 # will have been reported earlier.
518 pass
520 def free_temps(self, code):
521 if not self.is_temp:
522 self.free_subexpr_temps(code)
523 # otherwise, already freed in generate_evaluation_code
525 def free_subexpr_temps(self, code):
526 for sub in self.subexpr_nodes():
527 sub.free_temps(code)
529 # ---------------- Annotation ---------------------
531 def annotate(self, code):
532 for node in self.subexpr_nodes():
533 node.annotate(code)
535 # ----------------- Coercion ----------------------
537 def coerce_to(self, dst_type, env):
538 # Coerce the result so that it can be assigned to
539 # something of type dst_type. If processing is necessary,
540 # wraps this node in a coercion node and returns that.
541 # Otherwise, returns this node unchanged.
542 #
543 # This method is called during the analyse_expressions
544 # phase of the src_node's processing.
545 src = self
546 src_type = self.type
547 src_is_py_type = src_type.is_pyobject
548 dst_is_py_type = dst_type.is_pyobject
550 if dst_type.is_pyobject:
551 if not src.type.is_pyobject:
552 src = CoerceToPyTypeNode(src, env)
553 if not src.type.subtype_of(dst_type):
554 if not isinstance(src, NoneNode):
555 src = PyTypeTestNode(src, dst_type, env)
556 elif src.type.is_pyobject:
557 src = CoerceFromPyTypeNode(dst_type, src, env)
558 else: # neither src nor dst are py types
559 # Added the string comparison, since for c types that
560 # is enough, but Cython gets confused when the types are
561 # in different files.
562 if not (str(src.type) == str(dst_type) or dst_type.assignable_from(src_type)):
563 error(self.pos, "Cannot assign type '%s' to '%s'" %
564 (src.type, dst_type))
565 return src
567 def coerce_to_pyobject(self, env):
568 return self.coerce_to(PyrexTypes.py_object_type, env)
570 def coerce_to_boolean(self, env):
571 # Coerce result to something acceptable as
572 # a boolean value.
573 type = self.type
574 if type.is_pyobject or type.is_ptr or type.is_float:
575 return CoerceToBooleanNode(self, env)
576 else:
577 if not type.is_int and not type.is_error:
578 error(self.pos,
579 "Type '%s' not acceptable as a boolean" % type)
580 return self
582 def coerce_to_integer(self, env):
583 # If not already some C integer type, coerce to longint.
584 if self.type.is_int:
585 return self
586 else:
587 return self.coerce_to(PyrexTypes.c_long_type, env)
589 def coerce_to_temp(self, env):
590 # Ensure that the result is in a temporary.
591 if self.result_in_temp():
592 return self
593 else:
594 return CoerceToTempNode(self, env)
596 def coerce_to_simple(self, env):
597 # Ensure that the result is simple (see is_simple).
598 if self.is_simple():
599 return self
600 else:
601 return self.coerce_to_temp(env)
603 def is_simple(self):
604 # A node is simple if its result is something that can
605 # be referred to without performing any operations, e.g.
606 # a constant, local var, C global var, struct member
607 # reference, or temporary.
608 return self.result_in_temp()
610 def as_cython_attribute(self):
611 return None
614 class RemoveAllocateTemps(type):
615 def __init__(cls, name, bases, dct):
616 super(RemoveAllocateTemps, cls).__init__(name, bases, dct)
617 def noop(self, env): pass
618 setattr(cls, 'allocate_temps', noop)
619 setattr(cls, 'allocate_temp', noop)
620 setattr(cls, 'release_temp', noop)
622 class NewTempExprNode(ExprNode):
623 backwards_compatible_result = None
624 temp_code = None
625 old_temp = None # error checker for multiple frees etc.
627 # Do not enable this unless you are trying to make all ExprNodes
628 # NewTempExprNodes (child nodes reached via recursion may not have
629 # transferred).
630 # __metaclass__ = RemoveAllocateTemps
632 def result(self):
633 if self.is_temp:
634 return self.temp_code
635 else:
636 return self.calculate_result_code()
638 def allocate_target_temps(self, env, rhs):
639 self.allocate_subexpr_temps(env)
640 self.is_target = True
641 if rhs:
642 rhs.release_temp(env)
643 self.release_subexpr_temps(env)
645 def allocate_temps(self, env, result = None):
646 self.allocate_subexpr_temps(env)
647 self.backwards_compatible_result = result
648 if self.is_temp:
649 self.release_subexpr_temps(env)
651 def allocate_temp(self, env, result = None):
652 assert result is None
654 def release_temp(self, env):
655 if self.is_temp:
656 pass
657 else:
658 self.release_subexpr_temps(env)
660 def allocate_temp_result(self, code):
661 if self.temp_code:
662 raise RuntimeError("Temp allocated multiple times")
663 type = self.type
664 if not type.is_void:
665 if type.is_pyobject:
666 type = PyrexTypes.py_object_type
667 if self.backwards_compatible_result:
668 self.temp_code = self.backwards_compatible_result
669 else:
670 self.temp_code = code.funcstate.allocate_temp(
671 type, manage_ref=True)
672 else:
673 self.temp_code = None
675 def release_temp_result(self, code):
676 if not self.temp_code:
677 if self.old_temp:
678 raise RuntimeError("temp %s released multiple times in %s" % (
679 self.old_temp, self.__class__.__name__))
680 else:
681 raise RuntimeError("no temp, but release requested in %s" % (
682 self.__class__.__name__))
683 code.funcstate.release_temp(self.temp_code)
684 self.old_temp = self.temp_code
685 self.temp_code = None
687 def generate_evaluation_code(self, code):
688 code.mark_pos(self.pos)
690 # Generate code to evaluate this node and
691 # its sub-expressions, and dispose of any
692 # temporary results of its sub-expressions.
693 self.generate_subexpr_evaluation_code(code)
695 if self.is_temp:
696 self.allocate_temp_result(code)
698 self.generate_result_code(code)
699 if self.is_temp:
700 # If we are temp we do not need to wait until this node is disposed
701 # before disposing children.
702 self.generate_subexpr_disposal_code(code)
703 self.free_subexpr_temps(code)
705 def generate_disposal_code(self, code):
706 if self.is_temp:
707 if self.type.is_pyobject:
708 code.put_decref_clear(self.result(), self.ctype())
709 else:
710 # Already done if self.is_temp
711 self.generate_subexpr_disposal_code(code)
713 def generate_post_assignment_code(self, code):
714 if self.is_temp:
715 if self.type.is_pyobject:
716 code.putln("%s = 0;" % self.result())
717 else:
718 self.generate_subexpr_disposal_code(code)
720 def free_temps(self, code):
721 if self.is_temp:
722 if not self.type.is_void:
723 self.release_temp_result(code)
724 else:
725 self.free_subexpr_temps(code)
727 # ExprNode = NewTempExprNode
729 class AtomicExprNode(ExprNode):
730 # Abstract base class for expression nodes which have
731 # no sub-expressions.
733 subexprs = []
735 class AtomicNewTempExprNode(NewTempExprNode):
736 # I do not dare to convert NameNode yet. This is now
737 # ancestor of all former AtomicExprNode except
738 # NameNode. Should be renamed to AtomicExprNode
739 # when done.
741 # Abstract base class for expression nodes which have
742 # no sub-expressions.
744 subexprs = []
746 # Override to optimize -- we know we have no children
747 def generate_subexpr_evaluation_code(self, code):
748 pass
749 def generate_subexpr_disposal_code(self, code):
750 pass
752 class PyConstNode(AtomicNewTempExprNode):
753 # Abstract base class for constant Python values.
755 is_literal = 1
757 def is_simple(self):
758 return 1
760 def analyse_types(self, env):
761 self.type = py_object_type
763 def calculate_result_code(self):
764 return self.value
766 def generate_result_code(self, code):
767 pass
770 class NoneNode(PyConstNode):
771 # The constant value None
773 value = "Py_None"
775 constant_result = None
776 gil_check = None
778 def compile_time_value(self, denv):
779 return None
781 class EllipsisNode(PyConstNode):
782 # '...' in a subscript list.
784 value = "Py_Ellipsis"
786 constant_result = Ellipsis
788 def compile_time_value(self, denv):
789 return Ellipsis
792 class ConstNode(AtomicNewTempExprNode):
793 # Abstract base type for literal constant nodes.
794 #
795 # value string C code fragment
797 is_literal = 1
798 gil_check = None
800 def is_simple(self):
801 return 1
803 def analyse_types(self, env):
804 pass # Types are held in class variables
806 def check_const(self):
807 pass
809 def get_constant_result_code(self):
810 return self.calculate_result_code()
812 def calculate_result_code(self):
813 return str(self.value)
815 def generate_result_code(self, code):
816 pass
819 class BoolNode(ConstNode):
820 type = PyrexTypes.c_bint_type
821 # The constant value True or False
823 def calculate_constant_result(self):
824 self.constant_result = self.value
826 def compile_time_value(self, denv):
827 return self.value
829 def calculate_result_code(self):
830 return str(int(self.value))
833 class NullNode(ConstNode):
834 type = PyrexTypes.c_null_ptr_type
835 value = "NULL"
836 constant_result = 0
838 def get_constant_result_code(self):
839 return self.value
842 class CharNode(ConstNode):
843 type = PyrexTypes.c_char_type
845 def calculate_constant_result(self):
846 self.constant_result = ord(self.value)
848 def compile_time_value(self, denv):
849 return ord(self.value)
851 def calculate_result_code(self):
852 return "'%s'" % StringEncoding.escape_character(self.value)
855 class IntNode(ConstNode):
857 # unsigned "" or "U"
858 # longness "" or "L" or "LL"
860 unsigned = ""
861 longness = ""
862 type = PyrexTypes.c_long_type
864 def coerce_to(self, dst_type, env):
865 if dst_type.is_numeric:
866 self.type = PyrexTypes.c_long_type
867 return self
868 # Arrange for a Python version of the number to be pre-allocated
869 # when coercing to a Python type.
870 if dst_type.is_pyobject:
871 self.type = PyrexTypes.py_object_type
872 # We still need to perform normal coerce_to processing on the
873 # result, because we might be coercing to an extension type,
874 # in which case a type test node will be needed.
875 return ConstNode.coerce_to(self, dst_type, env)
877 def coerce_to_boolean(self, env):
878 self.type = PyrexTypes.c_bint_type
879 return self
881 def generate_evaluation_code(self, code):
882 if self.type.is_pyobject:
883 self.result_code = code.get_py_num(self.value, self.longness)
884 else:
885 self.result_code = self.get_constant_result_code()
887 def get_constant_result_code(self):
888 return str(self.value) + self.unsigned + self.longness
890 def calculate_result_code(self):
891 return self.result_code
893 def calculate_constant_result(self):
894 self.constant_result = int(self.value, 0)
896 def compile_time_value(self, denv):
897 return int(self.value, 0)
900 class FloatNode(ConstNode):
901 type = PyrexTypes.c_double_type
903 def calculate_constant_result(self):
904 # calculating float values is usually not a good idea
905 #self.constant_result = float(self.value)
906 pass
908 def compile_time_value(self, denv):
909 return float(self.value)
911 def calculate_result_code(self):
912 strval = repr(float(self.value))
913 if strval == 'nan':
914 return "(Py_HUGE_VAL * 0)"
915 elif strval == 'inf':
916 return "Py_HUGE_VAL"
917 elif strval == '-inf':
918 return "(-Py_HUGE_VAL)"
919 else:
920 return strval
923 class StringNode(ConstNode):
924 type = PyrexTypes.c_char_ptr_type
926 def compile_time_value(self, denv):
927 return self.value
929 def analyse_as_type(self, env):
930 type = PyrexTypes.parse_basic_type(self.value)
931 if type is not None:
932 return type
933 from TreeFragment import TreeFragment
934 pos = (self.pos[0], self.pos[1], self.pos[2]-7)
935 declaration = TreeFragment(u"sizeof(%s)" % self.value, name=pos[0].filename, initial_pos=pos)
936 sizeof_node = declaration.root.stats[0].expr
937 sizeof_node.analyse_types(env)
938 if isinstance(sizeof_node, SizeofTypeNode):
939 return sizeof_node.arg_type
941 def coerce_to(self, dst_type, env):
942 if dst_type == PyrexTypes.c_char_ptr_type:
943 self.type = PyrexTypes.c_char_ptr_type
944 return self
946 if dst_type.is_int:
947 if not self.type.is_pyobject and len(self.value) == 1:
948 return CharNode(self.pos, value=self.value)
949 else:
950 error(self.pos, "Only single-character byte strings can be coerced into ints.")
951 return self
952 # Arrange for a Python version of the string to be pre-allocated
953 # when coercing to a Python type.
954 if dst_type.is_pyobject and not self.type.is_pyobject:
955 node = self.as_py_string_node(env)
956 else:
957 node = self
958 # We still need to perform normal coerce_to processing on the
959 # result, because we might be coercing to an extension type,
960 # in which case a type test node will be needed.
961 return ConstNode.coerce_to(node, dst_type, env)
963 def as_py_string_node(self, env):
964 # Return a new StringNode with the same value as this node
965 # but whose type is a Python type instead of a C type.
966 return StringNode(self.pos, value = self.value, type = py_object_type)
968 def generate_evaluation_code(self, code):
969 if self.type.is_pyobject:
970 self.result_code = code.get_py_string_const(self.value)
971 else:
972 self.result_code = code.get_string_const(self.value)
974 def get_constant_result_code(self):
975 return None # FIXME
977 def calculate_result_code(self):
978 return self.result_code
981 class UnicodeNode(PyConstNode):
982 type = unicode_type
984 def coerce_to(self, dst_type, env):
985 if dst_type.is_pyobject:
986 return self
987 else:
988 error(self.pos, "Unicode objects do not support coercion to C types.")
989 return self
991 def generate_evaluation_code(self, code):
992 if self.type.is_pyobject:
993 self.result_code = code.get_py_string_const(self.value)
994 else:
995 self.result_code = code.get_string_const(self.value)
997 def calculate_result_code(self):
998 return self.result_code
1000 def compile_time_value(self, env):
1001 return self.value
1004 class IdentifierStringNode(ConstNode):
1005 # A Python string that behaves like an identifier, e.g. for
1006 # keyword arguments in a call, or for imported names
1007 type = PyrexTypes.py_object_type
1009 def generate_evaluation_code(self, code):
1010 if self.type.is_pyobject:
1011 self.result_code = code.get_py_string_const(self.value, True)
1012 else:
1013 self.result_code = code.get_string_const(self.value)
1015 def get_constant_result_code(self):
1016 return None
1018 def calculate_result_code(self):
1019 return self.result_code
1022 class LongNode(AtomicNewTempExprNode):
1023 # Python long integer literal
1025 # value string
1027 def calculate_constant_result(self):
1028 self.constant_result = long(self.value)
1030 def compile_time_value(self, denv):
1031 return long(self.value)
1033 def analyse_types(self, env):
1034 self.type = py_object_type
1035 self.is_temp = 1
1037 gil_message = "Constructing Python long int"
1039 def generate_result_code(self, code):
1040 code.putln(
1041 '%s = PyLong_FromString((char *)"%s", 0, 0); %s' % (
1042 self.result(),
1043 self.value,
1044 code.error_goto_if_null(self.result(), self.pos)))
1045 code.put_gotref(self.py_result())
1048 class ImagNode(AtomicNewTempExprNode):
1049 # Imaginary number literal
1051 # value float imaginary part
1053 def calculate_constant_result(self):
1054 self.constant_result = complex(0.0, self.value)
1056 def compile_time_value(self, denv):
1057 return complex(0.0, self.value)
1059 def analyse_types(self, env):
1060 self.type = py_object_type
1061 self.is_temp = 1
1063 gil_message = "Constructing complex number"
1065 def generate_result_code(self, code):
1066 code.putln(
1067 "%s = PyComplex_FromDoubles(0.0, %r); %s" % (
1068 self.result(),
1069 float(self.value),
1070 code.error_goto_if_null(self.result(), self.pos)))
1071 code.put_gotref(self.py_result())
1075 class NameNode(AtomicNewTempExprNode):
1076 # Reference to a local or global variable name.
1078 # name string Python name of the variable
1080 # entry Entry Symbol table entry
1082 is_name = True
1083 is_cython_module = False
1084 cython_attribute = None
1085 lhs_of_first_assignment = False
1086 is_used_as_rvalue = 0
1087 entry = None
1089 def create_analysed_rvalue(pos, env, entry):
1090 node = NameNode(pos)
1091 node.analyse_types(env, entry=entry)
1092 return node
1094 def as_cython_attribute(self):
1095 return self.cython_attribute
1097 create_analysed_rvalue = staticmethod(create_analysed_rvalue)
1099 def compile_time_value(self, denv):
1100 try:
1101 return denv.lookup(self.name)
1102 except KeyError:
1103 error(self.pos, "Compile-time name '%s' not defined" % self.name)
1105 def coerce_to(self, dst_type, env):
1106 # If coercing to a generic pyobject and this is a builtin
1107 # C function with a Python equivalent, manufacture a NameNode
1108 # referring to the Python builtin.
1109 #print "NameNode.coerce_to:", self.name, dst_type ###
1110 if dst_type is py_object_type:
1111 entry = self.entry
1112 if entry and entry.is_cfunction:
1113 var_entry = entry.as_variable
1114 if var_entry:
1115 if var_entry.is_builtin and Options.cache_builtins:
1116 var_entry = env.declare_builtin(var_entry.name, self.pos)
1117 node = NameNode(self.pos, name = self.name)
1118 node.entry = var_entry
1119 node.analyse_rvalue_entry(env)
1120 return node
1121 return super(NameNode, self).coerce_to(dst_type, env)
1123 def analyse_as_module(self, env):
1124 # Try to interpret this as a reference to a cimported module.
1125 # Returns the module scope, or None.
1126 entry = self.entry
1127 if not entry:
1128 entry = env.lookup(self.name)
1129 if entry and entry.as_module:
1130 return entry.as_module
1131 return None
1133 def analyse_as_type(self, env):
1134 if self.cython_attribute:
1135 type = PyrexTypes.parse_basic_type(self.cython_attribute)
1136 else:
1137 type = PyrexTypes.parse_basic_type(self.name)
1138 if type:
1139 return type
1140 entry = self.entry
1141 if not entry:
1142 entry = env.lookup(self.name)
1143 if entry and entry.is_type:
1144 return entry.type
1145 else:
1146 return None
1148 def analyse_as_extension_type(self, env):
1149 # Try to interpret this as a reference to an extension type.
1150 # Returns the extension type, or None.
1151 entry = self.entry
1152 if not entry:
1153 entry = env.lookup(self.name)
1154 if entry and entry.is_type and entry.type.is_extension_type:
1155 return entry.type
1156 else:
1157 return None
1159 def analyse_target_declaration(self, env):
1160 if not self.entry:
1161 self.entry = env.lookup_here(self.name)
1162 if not self.entry:
1163 self.entry = env.declare_var(self.name, py_object_type, self.pos)
1164 env.control_flow.set_state(self.pos, (self.name, 'initalized'), True)
1165 env.control_flow.set_state(self.pos, (self.name, 'source'), 'assignment')
1166 if self.entry.is_declared_generic:
1167 self.result_ctype = py_object_type
1169 def analyse_types(self, env):
1170 if self.entry is None:
1171 self.entry = env.lookup(self.name)
1172 if not self.entry:
1173 self.entry = env.declare_builtin(self.name, self.pos)
1174 if not self.entry:
1175 self.type = PyrexTypes.error_type
1176 return
1177 entry = self.entry
1178 if entry:
1179 entry.used = 1
1180 if entry.type.is_buffer:
1181 import Buffer
1182 Buffer.used_buffer_aux_vars(entry)
1183 if entry.utility_code:
1184 env.use_utility_code(entry.utility_code)
1185 self.analyse_rvalue_entry(env)
1187 def analyse_target_types(self, env):
1188 self.analyse_entry(env)
1189 if not self.is_lvalue():
1190 error(self.pos, "Assignment to non-lvalue '%s'"
1191 % self.name)
1192 self.type = PyrexTypes.error_type
1193 self.entry.used = 1
1194 if self.entry.type.is_buffer:
1195 import Buffer
1196 Buffer.used_buffer_aux_vars(self.entry)
1198 def analyse_rvalue_entry(self, env):
1199 #print "NameNode.analyse_rvalue_entry:", self.name ###
1200 #print "Entry:", self.entry.__dict__ ###
1201 self.analyse_entry(env)
1202 entry = self.entry
1203 if entry.is_declared_generic:
1204 self.result_ctype = py_object_type
1205 if entry.is_pyglobal or entry.is_builtin:
1206 if Options.cache_builtins and entry.is_builtin:
1207 self.is_temp = 0
1208 else:
1209 self.is_temp = 1
1210 self.is_used_as_rvalue = 1
1211 env.use_utility_code(get_name_interned_utility_code)
1213 def gil_check(self, env):
1214 if self.is_used_as_rvalue:
1215 entry = self.entry
1216 if entry.is_builtin:
1217 # if not Options.cache_builtins: # cached builtins are ok
1218 self._gil_check(env)
1219 elif entry.is_pyglobal:
1220 self._gil_check(env)
1222 gil_message = "Accessing Python global or builtin"
1224 def analyse_entry(self, env):
1225 #print "NameNode.analyse_entry:", self.name ###
1226 self.check_identifier_kind()
1227 entry = self.entry
1228 type = entry.type
1229 self.type = type
1231 def check_identifier_kind(self):
1232 #print "NameNode.check_identifier_kind:", self.entry.name ###
1233 #print self.entry.__dict__ ###
1234 entry = self.entry
1235 #entry.used = 1
1236 if not (entry.is_const or entry.is_variable
1237 or entry.is_builtin or entry.is_cfunction):
1238 if self.entry.as_variable:
1239 self.entry = self.entry.as_variable
1240 else:
1241 error(self.pos,
1242 "'%s' is not a constant, variable or function identifier" % self.name)
1244 def is_simple(self):
1245 # If it's not a C variable, it'll be in a temp.
1246 return 1
1248 def calculate_target_results(self, env):
1249 pass
1251 def check_const(self):
1252 entry = self.entry
1253 if entry is not None and not (entry.is_const or entry.is_cfunction or entry.is_builtin):
1254 self.not_const()
1256 def check_const_addr(self):
1257 entry = self.entry
1258 if not (entry.is_cglobal or entry.is_cfunction or entry.is_builtin):
1259 self.addr_not_const()
1261 def is_lvalue(self):
1262 return self.entry.is_variable and \
1263 not self.entry.type.is_array and \
1264 not self.entry.is_readonly
1266 def is_ephemeral(self):
1267 # Name nodes are never ephemeral, even if the
1268 # result is in a temporary.
1269 return 0
1271 def calculate_result_code(self):
1272 entry = self.entry
1273 if not entry:
1274 return "<error>" # There was an error earlier
1275 return entry.cname
1277 def generate_result_code(self, code):
1278 assert hasattr(self, 'entry')
1279 entry = self.entry
1280 if entry is None:
1281 return # There was an error earlier
1282 if entry.is_builtin and Options.cache_builtins:
1283 return # Lookup already cached
1284 elif entry.is_pyglobal or entry.is_builtin:
1285 assert entry.type.is_pyobject, "Python global or builtin not a Python object"
1286 interned_cname = code.intern_identifier(self.entry.name)
1287 if entry.is_builtin:
1288 namespace = Naming.builtins_cname
1289 else: # entry.is_pyglobal
1290 namespace = entry.scope.namespace_cname
1291 code.putln(
1292 '%s = __Pyx_GetName(%s, %s); %s' % (
1293 self.result(),
1294 namespace,
1295 interned_cname,
1296 code.error_goto_if_null(self.result(), self.pos)))
1297 code.put_gotref(self.py_result())
1299 elif entry.is_local and False:
1300 # control flow not good enough yet
1301 assigned = entry.scope.control_flow.get_state((entry.name, 'initalized'), self.pos)
1302 if assigned is False:
1303 error(self.pos, "local variable '%s' referenced before assignment" % entry.name)
1304 elif not Options.init_local_none and assigned is None:
1305 code.putln('if (%s == 0) { PyErr_SetString(PyExc_UnboundLocalError, "%s"); %s }' %
1306 (entry.cname, entry.name, code.error_goto(self.pos)))
1307 entry.scope.control_flow.set_state(self.pos, (entry.name, 'initalized'), True)
1309 def generate_assignment_code(self, rhs, code):
1310 #print "NameNode.generate_assignment_code:", self.name ###
1311 entry = self.entry
1312 if entry is None:
1313 return # There was an error earlier
1315 if (self.entry.type.is_ptr and isinstance(rhs, ListNode)
1316 and not self.lhs_of_first_assignment):
1317 error(self.pos, "Literal list must be assigned to pointer at time of declaration")
1319 # is_pyglobal seems to be True for module level-globals only.
1320 # We use this to access class->tp_dict if necessary.
1321 if entry.is_pyglobal:
1322 assert entry.type.is_pyobject, "Python global or builtin not a Python object"
1323 interned_cname = code.intern_identifier(self.entry.name)
1324 namespace = self.entry.scope.namespace_cname
1325 if entry.is_member:
1326 # if the entry is a member we have to cheat: SetAttr does not work
1327 # on types, so we create a descriptor which is then added to tp_dict
1328 code.put_error_if_neg(self.pos,
1329 'PyDict_SetItem(%s->tp_dict, %s, %s)' % (
1330 namespace,
1331 interned_cname,
1332 rhs.py_result()))
1333 rhs.generate_disposal_code(code)
1334 rhs.free_temps(code)
1335 # in Py2.6+, we need to invalidate the method cache
1336 code.putln("PyType_Modified(%s);" %
1337 entry.scope.parent_type.typeptr_cname)
1338 else:
1339 code.put_error_if_neg(self.pos,
1340 'PyObject_SetAttr(%s, %s, %s)' % (
1341 namespace,
1342 interned_cname,
1343 rhs.py_result()))
1344 if debug_disposal_code:
1345 print("NameNode.generate_assignment_code:")
1346 print("...generating disposal code for %s" % rhs)
1347 rhs.generate_disposal_code(code)
1348 rhs.free_temps(code)
1349 else:
1350 if self.type.is_buffer:
1351 # Generate code for doing the buffer release/acquisition.
1352 # This might raise an exception in which case the assignment (done
1353 # below) will not happen.
1355 # The reason this is not in a typetest-like node is because the
1356 # variables that the acquired buffer info is stored to is allocated
1357 # per entry and coupled with it.
1358 self.generate_acquire_buffer(rhs, code)
1360 if self.type.is_pyobject:
1361 rhs.make_owned_reference(code)
1362 #print "NameNode.generate_assignment_code: to", self.name ###
1363 #print "...from", rhs ###
1364 #print "...LHS type", self.type, "ctype", self.ctype() ###
1365 #print "...RHS type", rhs.type, "ctype", rhs.ctype() ###
1366 if entry.is_cglobal:
1367 code.put_gotref(self.py_result())
1368 if not self.lhs_of_first_assignment:
1369 if entry.is_local and not Options.init_local_none:
1370 initalized = entry.scope.control_flow.get_state((entry.name, 'initalized'), self.pos)
1371 if initalized is True:
1372 code.put_decref(self.result(), self.ctype())
1373 elif initalized is None:
1374 code.put_xdecref(self.result(), self.ctype())
1375 else:
1376 code.put_decref(self.result(), self.ctype())
1377 if entry.is_cglobal:
1378 code.put_giveref(rhs.py_result())
1379 code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
1380 if debug_disposal_code:
1381 print("NameNode.generate_assignment_code:")
1382 print("...generating post-assignment code for %s" % rhs)
1383 rhs.generate_post_assignment_code(code)
1384 rhs.free_temps(code)
1386 def generate_acquire_buffer(self, rhs, code):
1387 # rhstmp is only used in case the rhs is a complicated expression leading to
1388 # the object, to avoid repeating the same C expression for every reference
1389 # to the rhs. It does NOT hold a reference.
1390 pretty_rhs = isinstance(rhs, NameNode) or rhs.is_temp
1391 if pretty_rhs:
1392 rhstmp = rhs.result_as(self.ctype())
1393 else:
1394 rhstmp = code.funcstate.allocate_temp(self.entry.type, manage_ref=False)
1395 code.putln('%s = %s;' % (rhstmp, rhs.result_as(self.ctype())))
1397 buffer_aux = self.entry.buffer_aux
1398 bufstruct = buffer_aux.buffer_info_var.cname
1399 import Buffer
1400 Buffer.put_assign_to_buffer(self.result(), rhstmp, buffer_aux, self.entry.type,
1401 is_initialized=not self.lhs_of_first_assignment,
1402 pos=self.pos, code=code)
1404 if not pretty_rhs:
1405 code.putln("%s = 0;" % rhstmp)
1406 code.funcstate.release_temp(rhstmp)
1408 def generate_deletion_code(self, code):
1409 if self.entry is None:
1410 return # There was an error earlier
1411 if not self.entry.is_pyglobal:
1412 error(self.pos, "Deletion of local or C global name not supported")
1413 return
1414 code.put_error_if_neg(self.pos,
1415 '__Pyx_DelAttrString(%s, "%s")' % (
1416 Naming.module_cname,
1417 self.entry.name))
1419 def annotate(self, code):
1420 if hasattr(self, 'is_called') and self.is_called:
1421 pos = (self.pos[0], self.pos[1], self.pos[2] - len(self.name) - 1)
1422 if self.type.is_pyobject:
1423 code.annotate(pos, AnnotationItem('py_call', 'python function', size=len(self.name)))
1424 else:
1425 code.annotate(pos, AnnotationItem('c_call', 'c function', size=len(self.name)))
1427 class BackquoteNode(NewTempExprNode):
1428 # `expr`
1430 # arg ExprNode
1432 subexprs = ['arg']
1434 def analyse_types(self, env):
1435 self.arg.analyse_types(env)
1436 self.arg = self.arg.coerce_to_pyobject(env)
1437 self.type = py_object_type
1438 self.is_temp = 1
1440 gil_message = "Backquote expression"
1442 def calculate_constant_result(self):
1443 self.constant_result = repr(self.arg.constant_result)
1445 def generate_result_code(self, code):
1446 code.putln(
1447 "%s = PyObject_Repr(%s); %s" % (
1448 self.result(),
1449 self.arg.py_result(),
1450 code.error_goto_if_null(self.result(), self.pos)))
1451 code.put_gotref(self.py_result())
1455 class ImportNode(NewTempExprNode):
1456 # Used as part of import statement implementation.
1457 # Implements result =
1458 # __import__(module_name, globals(), None, name_list)
1460 # module_name IdentifierStringNode dotted name of module
1461 # name_list ListNode or None list of names to be imported
1463 subexprs = ['module_name', 'name_list']
1465 def analyse_types(self, env):
1466 self.module_name.analyse_types(env)
1467 self.module_name = self.module_name.coerce_to_pyobject(env)
1468 if self.name_list:
1469 self.name_list.analyse_types(env)
1470 self.name_list.coerce_to_pyobject(env)
1471 self.type = py_object_type
1472 self.is_temp = 1
1473 env.use_utility_code(import_utility_code)
1475 gil_message = "Python import"
1477 def generate_result_code(self, code):
1478 if self.name_list:
1479 name_list_code = self.name_list.py_result()
1480 else:
1481 name_list_code = "0"
1482 code.putln(
1483 "%s = __Pyx_Import(%s, %s); %s" % (
1484 self.result(),
1485 self.module_name.py_result(),
1486 name_list_code,
1487 code.error_goto_if_null(self.result(), self.pos)))
1488 code.put_gotref(self.py_result())
1491 class IteratorNode(NewTempExprNode):
1492 # Used as part of for statement implementation.
1494 # allocate_counter_temp/release_counter_temp needs to be called
1495 # by parent (ForInStatNode)
1497 # Implements result = iter(sequence)
1499 # sequence ExprNode
1501 subexprs = ['sequence']
1503 def analyse_types(self, env):
1504 self.sequence.analyse_types(env)
1505 self.sequence = self.sequence.coerce_to_pyobject(env)
1506 self.type = py_object_type
1507 self.is_temp = 1
1509 gil_message = "Iterating over Python object"
1511 def allocate_counter_temp(self, code):
1512 self.counter_cname = code.funcstate.allocate_temp(
1513 PyrexTypes.c_py_ssize_t_type, manage_ref=False)
1515 def release_counter_temp(self, code):
1516 code.funcstate.release_temp(self.counter_cname)
1518 def generate_result_code(self, code):
1519 is_builtin_sequence = self.sequence.type is list_type or \
1520 self.sequence.type is tuple_type
1521 if is_builtin_sequence:
1522 code.putln(
1523 "if (likely(%s != Py_None)) {" % self.sequence.py_result())
1524 else:
1525 code.putln(
1526 "if (PyList_CheckExact(%s) || PyTuple_CheckExact(%s)) {" % (
1527 self.sequence.py_result(),
1528 self.sequence.py_result()))
1529 code.putln(
1530 "%s = 0; %s = %s; __Pyx_INCREF(%s);" % (
1531 self.counter_cname,
1532 self.result(),
1533 self.sequence.py_result(),
1534 self.result()))
1535 code.putln("} else {")
1536 if is_builtin_sequence:
1537 code.putln(
1538 'PyErr_SetString(PyExc_TypeError, "\'NoneType\' object is not iterable"); %s' %
1539 code.error_goto(self.pos))
1540 else:
1541 code.putln("%s = -1; %s = PyObject_GetIter(%s); %s" % (
1542 self.counter_cname,
1543 self.result(),
1544 self.sequence.py_result(),
1545 code.error_goto_if_null(self.result(), self.pos)))
1546 code.put_gotref(self.py_result())
1547 code.putln("}")
1550 class NextNode(AtomicNewTempExprNode):
1551 # Used as part of for statement implementation.
1552 # Implements result = iterator.next()
1553 # Created during analyse_types phase.
1554 # The iterator is not owned by this node.
1556 # iterator ExprNode
1558 def __init__(self, iterator, env):
1559 self.pos = iterator.pos
1560 self.iterator = iterator
1561 self.type = py_object_type
1562 self.is_temp = 1
1564 def generate_result_code(self, code):
1565 if self.iterator.sequence.type is list_type:
1566 type_checks = [(list_type, "List")]
1567 elif self.iterator.sequence.type is tuple_type:
1568 type_checks = [(tuple_type, "Tuple")]
1569 else:
1570 type_checks = [(list_type, "List"), (tuple_type, "Tuple")]
1572 for py_type, prefix in type_checks:
1573 if len(type_checks) > 1:
1574 code.putln(
1575 "if (likely(Py%s_CheckExact(%s))) {" % (
1576 prefix, self.iterator.py_result()))
1577 code.putln(
1578 "if (%s >= Py%s_GET_SIZE(%s)) break;" % (
1579 self.iterator.counter_cname,
1580 prefix,
1581 self.iterator.py_result()))
1582 code.putln(
1583 "%s = Py%s_GET_ITEM(%s, %s); __Pyx_INCREF(%s); %s++;" % (
1584 self.result(),
1585 prefix,
1586 self.iterator.py_result(),
1587 self.iterator.counter_cname,
1588 self.result(),
1589 self.iterator.counter_cname))
1590 if len(type_checks) > 1:
1591 code.put("} else ")
1592 if len(type_checks) == 1:
1593 return
1594 code.putln("{")
1595 code.putln(
1596 "%s = PyIter_Next(%s);" % (
1597 self.result(),
1598 self.iterator.py_result()))
1599 code.putln(
1600 "if (!%s) {" %
1601 self.result())
1602 code.putln(code.error_goto_if_PyErr(self.pos))
1603 code.putln("break;")
1604 code.putln("}")
1605 code.put_gotref(self.py_result())
1606 code.putln("}")
1609 class ExcValueNode(AtomicNewTempExprNode):
1610 # Node created during analyse_types phase
1611 # of an ExceptClauseNode to fetch the current
1612 # exception value.
1614 def __init__(self, pos, env, var):
1615 ExprNode.__init__(self, pos)
1616 self.type = py_object_type
1617 self.var = var
1619 def calculate_result_code(self):
1620 return self.var
1622 def generate_result_code(self, code):
1623 pass
1625 def analyse_types(self, env):
1626 pass
1629 class TempNode(ExprNode):
1630 # Node created during analyse_types phase
1631 # of some nodes to hold a temporary value.
1633 subexprs = []
1635 def __init__(self, pos, type, env):
1636 ExprNode.__init__(self, pos)
1637 self.type = type
1638 if type.is_pyobject:
1639 self.result_ctype = py_object_type
1640 self.is_temp = 1
1642 def analyse_types(self, env):
1643 return self.type
1645 def generate_result_code(self, code):
1646 pass
1649 class PyTempNode(TempNode):
1650 # TempNode holding a Python value.
1652 def __init__(self, pos, env):
1653 TempNode.__init__(self, pos, PyrexTypes.py_object_type, env)
1656 #-------------------------------------------------------------------
1658 # Trailer nodes
1660 #-------------------------------------------------------------------
1662 class IndexNode(ExprNode):
1663 # Sequence indexing.
1665 # base ExprNode
1666 # index ExprNode
1667 # indices [ExprNode]
1668 # is_buffer_access boolean Whether this is a buffer access.
1670 # indices is used on buffer access, index on non-buffer access.
1671 # The former contains a clean list of index parameters, the
1672 # latter whatever Python object is needed for index access.
1674 subexprs = ['base', 'index', 'indices']
1675 indices = None
1677 def __init__(self, pos, index, *args, **kw):
1678 ExprNode.__init__(self, pos, index=index, *args, **kw)
1679 self._index = index
1681 def calculate_constant_result(self):
1682 self.constant_result = \
1683 self.base.constant_result[self.index.constant_result]
1685 def compile_time_value(self, denv):
1686 base = self.base.compile_time_value(denv)
1687 index = self.index.compile_time_value(denv)
1688 try:
1689 return base[index]
1690 except Exception, e:
1691 self.compile_time_value_error(e)
1693 def is_ephemeral(self):
1694 return self.base.is_ephemeral()
1696 def analyse_target_declaration(self, env):
1697 pass
1699 def analyse_as_type(self, env):
1700 base_type = self.base.analyse_as_type(env)
1701 if base_type and not base_type.is_pyobject:
1702 return PyrexTypes.CArrayType(base_type, int(self.index.compile_time_value(env)))
1703 return None
1705 def analyse_types(self, env):
1706 self.analyse_base_and_index_types(env, getting = 1)
1708 def analyse_target_types(self, env):
1709 self.analyse_base_and_index_types(env, setting = 1)
1711 def analyse_base_and_index_types(self, env, getting = 0, setting = 0):
1712 # Note: This might be cleaned up by having IndexNode
1713 # parsed in a saner way and only construct the tuple if
1714 # needed.
1716 # Note that this function must leave IndexNode in a cloneable state.
1717 # For buffers, self.index is packed out on the initial analysis, and
1718 # when cloning self.indices is copied.
1719 self.is_buffer_access = False
1721 self.base.analyse_types(env)
1722 # Handle the case where base is a literal char* (and we expect a string, not an int)
1723 if isinstance(self.base, StringNode):
1724 self.base = self.base.coerce_to_pyobject(env)
1726 skip_child_analysis = False
1727 buffer_access = False
1728 if self.base.type.is_buffer:
1729 assert hasattr(self.base, "entry") # Must be a NameNode-like node
1730 if self.indices:
1731 indices = self.indices
1732 else:
1733 # On cloning, indices is cloned. Otherwise, unpack index into indices
1734 assert not isinstance(self.index, CloneNode)
1735 if isinstance(self.index, TupleNode):
1736 indices = self.index.args
1737 else:
1738 indices = [self.index]
1739 if len(indices) == self.base.type.ndim:
1740 buffer_access = True
1741 skip_child_analysis = True
1742 for x in indices:
1743 x.analyse_types(env)
1744 if not x.type.is_int:
1745 buffer_access = False
1747 if buffer_access:
1748 self.indices = indices
1749 self.index = None
1750 self.type = self.base.type.dtype
1751 self.is_buffer_access = True
1752 self.buffer_type = self.base.entry.type
1754 if getting and self.type.is_pyobject:
1755 self.is_temp = True
1756 if setting:
1757 if not self.base.entry.type.writable:
1758 error(self.pos, "Writing to readonly buffer")
1759 else:
1760 self.base.entry.buffer_aux.writable_needed = True
1761 else:
1762 if isinstance(self.index, TupleNode):
1763 self.index.analyse_types(env, skip_children=skip_child_analysis)
1764 elif not skip_child_analysis:
1765 self.index.analyse_types(env)
1766 self.original_index_type = self.index.type
1767 if self.base.type.is_pyobject:
1768 if self.index.type.is_int:
1769 self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env).coerce_to_simple(env)
1770 else:
1771 self.index = self.index.coerce_to_pyobject(env)
1772 self.type = py_object_type
1773 self.is_temp = 1
1774 else:
1775 if self.base.type.is_ptr or self.base.type.is_array:
1776 self.type = self.base.type.base_type
1777 else:
1778 error(self.pos,
1779 "Attempting to index non-array type '%s'" %
1780 self.base.type)
1781 self.type = PyrexTypes.error_type
1782 if self.index.type.is_pyobject:
1783 self.index = self.index.coerce_to(
1784 PyrexTypes.c_py_ssize_t_type, env)
1785 if not self.index.type.is_int:
1786 error(self.pos,
1787 "Invalid index type '%s'" %
1788 self.index.type)
1790 def gil_check(self, env):
1791 if not self.is_buffer_access:
1792 if self.base.type.is_pyobject:
1793 self._gil_check(env)
1795 gil_message = "Indexing Python object"
1797 def check_const_addr(self):
1798 self.base.check_const_addr()
1799 self.index.check_const()
1801 def is_lvalue(self):
1802 return 1
1804 def calculate_result_code(self):
1805 if self.is_buffer_access:
1806 return "(*%s)" % self.buffer_ptr_code
1807 else:
1808 return "(%s[%s])" % (
1809 self.base.result(), self.index.result())
1811 def extra_index_params(self):
1812 if self.index.type.is_int:
1813 if self.original_index_type.signed:
1814 size_adjustment = ""
1815 else:
1816 size_adjustment = "+1"
1817 return ", sizeof(%s)%s, %s" % (self.original_index_type.declaration_code(""), size_adjustment, self.original_index_type.to_py_function)
1818 else:
1819 return ""
1821 def generate_subexpr_evaluation_code(self, code):
1822 self.base.generate_evaluation_code(code)
1823 if not self.indices:
1824 self.index.generate_evaluation_code(code)
1825 else:
1826 for i in self.indices:
1827 i.generate_evaluation_code(code)
1829 def generate_subexpr_disposal_code(self, code):
1830 self.base.generate_disposal_code(code)
1831 if not self.indices:
1832 self.index.generate_disposal_code(code)
1833 else:
1834 for i in self.indices:
1835 i.generate_disposal_code(code)
1837 def free_subexpr_temps(self, code):
1838 self.base.free_temps(code)
1839 if not self.indices:
1840 self.index.free_temps(code)
1841 else:
1842 for i in self.indices:
1843 i.free_temps(code)
1845 def generate_result_code(self, code):
1846 if self.is_buffer_access:
1847 if code.globalstate.directives['nonecheck']:
1848 self.put_nonecheck(code)
1849 self.buffer_ptr_code = self.buffer_lookup_code(code)
1850 if self.type.is_pyobject:
1851 # is_temp is True, so must pull out value and incref it.
1852 code.putln("%s = *%s;" % (self.result(), self.buffer_ptr_code))
1853 code.putln("__Pyx_INCREF((PyObject*)%s);" % self.result())
1854 elif self.type.is_pyobject:
1855 if self.index.type.is_int:
1856 index_code = self.index.result()
1857 if self.base.type is list_type:
1858 function = "__Pyx_GetItemInt_List"
1859 elif self.base.type is tuple_type:
1860 function = "__Pyx_GetItemInt_Tuple"
1861 else:
1862 function = "__Pyx_GetItemInt"
1863 code.globalstate.use_utility_code(getitem_int_utility_code)
1864 else:
1865 function = "PyObject_GetItem"
1866 index_code = self.index.py_result()
1867 sign_code = ""
1868 code.putln(
1869 "%s = %s(%s, %s%s); if (!%s) %s" % (
1870 self.result(),
1871 function,
1872 self.base.py_result(),
1873 index_code,
1874 self.extra_index_params(),
1875 self.result(),
1876 code.error_goto(self.pos)))
1877 code.put_gotref(self.py_result())
1879 def generate_setitem_code(self, value_code, code):
1880 if self.index.type.is_int:
1881 function = "__Pyx_SetItemInt"
1882 index_code = self.index.result()
1883 code.globalstate.use_utility_code(setitem_int_utility_code)
1884 else:
1885 index_code = self.index.py_result()
1886 if self.base.type is dict_type:
1887 function = "PyDict_SetItem"
1888 elif self.base.type is list_type:
1889 function = "PyList_SetItem"
1890 # don't use PyTuple_SetItem(), as we'd normally get a
1891 # TypeError when changing a tuple, while PyTuple_SetItem()
1892 # would allow updates
1894 #elif self.base.type is tuple_type:
1895 # function = "PyTuple_SetItem"
1896 else:
1897 function = "PyObject_SetItem"
1898 code.putln(
1899 "if (%s(%s, %s, %s%s) < 0) %s" % (
1900 function,
1901 self.base.py_result(),
1902 index_code,
1903 value_code,
1904 self.extra_index_params(),
1905 code.error_goto(self.pos)))
1907 def generate_buffer_setitem_code(self, rhs, code, op=""):
1908 # Used from generate_assignment_code and InPlaceAssignmentNode
1909 if code.globalstate.directives['nonecheck']:
1910 self.put_nonecheck(code)
1911 ptrexpr = self.buffer_lookup_code(code)
1912 if self.buffer_type.dtype.is_pyobject:
1913 # Must manage refcounts. Decref what is already there
1914 # and incref what we put in.
1915 ptr = code.funcstate.allocate_temp(self.buffer_type.buffer_ptr_type, manage_ref=False)
1916 rhs_code = rhs.result()
1917 code.putln("%s = %s;" % (ptr, ptrexpr))
1918 code.put_gotref("*%s" % ptr)
1919 code.putln("__Pyx_DECREF(*%s); __Pyx_INCREF(%s);" % (
1920 ptr, rhs_code
1921 ))
1922 code.putln("*%s %s= %s;" % (ptr, op, rhs_code))
1923 code.put_giveref("*%s" % ptr)
1924 code.funcstate.release_temp(ptr)
1925 else:
1926 # Simple case
1927 code.putln("*%s %s= %s;" % (ptrexpr, op, rhs.result()))
1929 def generate_assignment_code(self, rhs, code):
1930 self.generate_subexpr_evaluation_code(code)
1931 if self.is_buffer_access:
1932 self.generate_buffer_setitem_code(rhs, code)
1933 elif self.type.is_pyobject:
1934 self.generate_setitem_code(rhs.py_result(), code)
1935 else:
1936 code.putln(
1937 "%s = %s;" % (
1938 self.result(), rhs.result()))
1939 self.generate_subexpr_disposal_code(code)
1940 self.free_subexpr_temps(code)
1941 rhs.generate_disposal_code(code)
1942 rhs.free_temps(code)
1944 def generate_deletion_code(self, code):
1945 self.generate_subexpr_evaluation_code(code)
1946 #if self.type.is_pyobject:
1947 if self.index.type.is_int:
1948 function = "__Pyx_DelItemInt"
1949 index_code = self.index.result()
1950 code.globalstate.use_utility_code(delitem_int_utility_code)
1951 else:
1952 index_code = self.index.py_result()
1953 if self.base.type is dict_type:
1954 function = "PyDict_DelItem"
1955 else:
1956 function = "PyObject_DelItem"
1957 code.putln(
1958 "if (%s(%s, %s%s) < 0) %s" % (
1959 function,
1960 self.base.py_result(),
1961 index_code,
1962 self.extra_index_params(),
1963 code.error_goto(self.pos)))
1964 self.generate_subexpr_disposal_code(code)
1965 self.free_subexpr_temps(code)
1967 def buffer_lookup_code(self, code):
1968 # Assign indices to temps
1969 index_temps = [code.funcstate.allocate_temp(i.type, manage_ref=False) for i in self.indices]
1970 for temp, index in zip(index_temps, self.indices):
1971 code.putln("%s = %s;" % (temp, index.result()))
1972 # Generate buffer access code using these temps
1973 import Buffer
1974 # The above could happen because child_attrs is wrong somewhere so that
1975 # options are not propagated.
1976 return Buffer.put_buffer_lookup_code(entry=self.base.entry,
1977 index_signeds=[i.type.signed for i in self.indices],
1978 index_cnames=index_temps,
1979 options=code.globalstate.directives,
1980 pos=self.pos, code=code)
1982 def put_nonecheck(self, code):
1983 code.globalstate.use_utility_code(raise_noneindex_error_utility_code)
1984 code.putln("if (%s) {" % code.unlikely("%s == Py_None") % self.base.result_as(PyrexTypes.py_object_type))
1985 code.putln("__Pyx_RaiseNoneIndexingError();")
1986 code.putln(code.error_goto(self.pos))
1987 code.putln("}")
1989 class SliceIndexNode(NewTempExprNode):
1990 # 2-element slice indexing
1992 # base ExprNode
1993 # start ExprNode or None
1994 # stop ExprNode or None
1996 subexprs = ['base', 'start', 'stop']
1998 def calculate_constant_result(self):
1999 self.constant_result = self.base.constant_result[
2000 self.start.constant_result : self.stop.constant_result]
2002 def compile_time_value(self, denv):
2003 base = self.base.compile_time_value(denv)
2004 if self.start is None:
2005 start = 0
2006 else:
2007 start = self.start.compile_time_value(denv)
2008 if self.stop is None:
2009 stop = None
2010 else:
2011 stop = self.stop.compile_time_value(denv)
2012 try:
2013 return base[start:stop]
2014 except Exception, e:
2015 self.compile_time_value_error(e)
2017 def analyse_target_declaration(self, env):
2018 pass
2020 def analyse_types(self, env):
2021 self.base.analyse_types(env)
2022 if self.start:
2023 self.start.analyse_types(env)
2024 if self.stop:
2025 self.stop.analyse_types(env)
2026 if self.base.type.is_string:
2027 self.type = py_object_type
2028 elif self.base.type.is_array or self.base.type.is_ptr:
2029 # we need a ptr type here instead of an array type, as
2030 # array types can result in invalid type casts in the C
2031 # code
2032 self.type = PyrexTypes.CPtrType(self.base.type.base_type)
2033 else:
2034 self.base = self.base.coerce_to_pyobject(env)
2035 self.type = py_object_type
2036 c_int = PyrexTypes.c_py_ssize_t_type
2037 if self.start:
2038 self.start = self.start.coerce_to(c_int, env)
2039 if self.stop:
2040 self.stop = self.stop.coerce_to(c_int, env)
2041 self.is_temp = 1
2043 gil_check = ExprNode._gil_check
2044 gil_message = "Slicing Python object"
2046 def generate_result_code(self, code):
2047 if not self.type.is_pyobject:
2048 error(self.pos,
2049 "Slicing is not currently supported for '%s'." % self.type)
2050 return
2051 if self.base.type.is_string:
2052 if self.stop is None:
2053 code.putln(
2054 "%s = __Pyx_PyBytes_FromString(%s + %s); %s" % (
2055 self.result(),
2056 self.base.result(),
2057 self.start_code(),
2058 code.error_goto_if_null(self.result(), self.pos)))
2059 else:
2060 code.putln(
2061 "%s = __Pyx_PyBytes_FromStringAndSize(%s + %s, %s - %s); %s" % (
2062 self.result(),
2063 self.base.result(),
2064 self.start_code(),
2065 self.stop_code(),
2066 self.start_code(),
2067 code.error_goto_if_null(self.result(), self.pos)))
2068 else:
2069 code.putln(
2070 "%s = PySequence_GetSlice(%s, %s, %s); %s" % (
2071 self.result(),
2072 self.base.py_result(),
2073 self.start_code(),
2074 self.stop_code(),
2075 code.error_goto_if_null(self.result(), self.pos)))
2076 code.put_gotref(self.py_result())
2078 def generate_assignment_code(self, rhs, code):
2079 self.generate_subexpr_evaluation_code(code)
2080 if self.type.is_pyobject:
2081 code.put_error_if_neg(self.pos,
2082 "PySequence_SetSlice(%s, %s, %s, %s)" % (
2083 self.base.py_result(),
2084 self.start_code(),
2085 self.stop_code(),
2086 rhs.result()))
2087 else:
2088 start_offset = ''
2089 if self.start:
2090 start_offset = self.start_code()
2091 if start_offset == '0':
2092 start_offset = ''
2093 else:
2094 start_offset += '+'
2095 if rhs.type.is_array:
2096 array_length = rhs.type.size
2097 self.generate_slice_guard_code(code, array_length)
2098 else:
2099 error("Slice assignments from pointers are not yet supported.")
2100 # FIXME: fix the array size according to start/stop
2101 array_length = self.base.type.size
2102 for i in range(array_length):
2103 code.putln("%s[%s%s] = %s[%d];" % (
2104 self.base.result(), start_offset, i,
2105 rhs.result(), i))
2106 self.generate_subexpr_disposal_code(code)
2107 self.free_subexpr_temps(code)
2108 rhs.generate_disposal_code(code)
2109 rhs.free_temps(code)
2111 def generate_deletion_code(self, code):
2112 if not self.base.type.is_pyobject:
2113 error(self.pos,
2114 "Deleting slices is only supported for Python types, not '%s'." % self.type)
2115 return
2116 self.generate_subexpr_evaluation_code(code)
2117 code.put_error_if_neg(self.pos,
2118 "PySequence_DelSlice(%s, %s, %s)" % (
2119 self.base.py_result(),
2120 self.start_code(),
2121 self.stop_code()))
2122 self.generate_subexpr_disposal_code(code)
2124 def generate_slice_guard_code(self, code, target_size):
2125 if not self.base.type.is_array:
2126 return
2127 slice_size = self.base.type.size
2128 start = stop = None
2129 if self.stop:
2130 stop = self.stop.result()
2131 try:
2132 stop = int(stop)
2133 if stop < 0:
2134 slice_size = self.base.type.size + stop
2135 else:
2136 slice_size = stop
2137 stop = None
2138 except ValueError:
2139 pass
2140 if self.start:
2141 start = self.start.result()
2142 try:
2143 start = int(start)
2144 if start < 0:
2145 start = self.base.type.size + start
2146 slice_size -= start
2147 start = None
2148 except ValueError:
2149 pass
2150 check = None
2151 if slice_size < 0:
2152 if target_size > 0:
2153 error(self.pos, "Assignment to empty slice.")
2154 elif start is None and stop is None:
2155 # we know the exact slice length
2156 if target_size != slice_size:
2157 error(self.pos, "Assignment to slice of wrong length, expected %d, got %d" % (
2158 slice_size, target_size))
2159 elif start is not None:
2160 if stop is None:
2161 stop = slice_size
2162 check = "(%s)-(%s)" % (stop, start)
2163 else: # stop is not None:
2164 check = stop
2165 if check:
2166 code.putln("if (unlikely((%s) != %d)) {" % (check, target_size))
2167 code.putln('PyErr_Format(PyExc_ValueError, "Assignment to slice of wrong length, expected %%d, got %%d", %d, (%s));' % (
2168 target_size, check))
2169 code.putln(code.error_goto(self.pos))
2170 code.putln("}")
2172 def start_code(self):
2173 if self.start:
2174 return self.start.result()
2175 else:
2176 return "0"
2178 def stop_code(self):
2179 if self.stop:
2180 return self.stop.result()
2181 elif self.base.type.is_array:
2182 return self.base.type.size
2183 else:
2184 return "PY_SSIZE_T_MAX"
2186 def calculate_result_code(self):
2187 # self.result() is not used, but this method must exist
2188 return "<unused>"
2191 class SliceNode(NewTempExprNode):
2192 # start:stop:step in subscript list
2194 # start ExprNode
2195 # stop ExprNode
2196 # step ExprNode
2198 def calculate_constant_result(self):
2199 self.constant_result = self.base.constant_result[
2200 self.start.constant_result : \
2201 self.stop.constant_result : \
2202 self.step.constant_result]
2204 def compile_time_value(self, denv):
2205 start = self.start.compile_time_value(denv)
2206 if self.stop is None:
2207 stop = None
2208 else:
2209 stop = self.stop.compile_time_value(denv)
2210 if self.step is None:
2211 step = None
2212 else:
2213 step = self.step.compile_time_value(denv)
2214 try:
2215 return slice(start, stop, step)
2216 except Exception, e:
2217 self.compile_time_value_error(e)
2219 subexprs = ['start', 'stop', 'step']
2221 def analyse_types(self, env):
2222 self.start.analyse_types(env)
2223 self.stop.analyse_types(env)
2224 self.step.analyse_types(env)
2225 self.start = self.start.coerce_to_pyobject(env)
2226 self.stop = self.stop.coerce_to_pyobject(env)
2227 self.step = self.step.coerce_to_pyobject(env)
2228 self.type = py_object_type
2229 self.is_temp = 1
2231 gil_message = "Constructing Python slice object"
2233 def generate_result_code(self, code):
2234 code.putln(
2235 "%s = PySlice_New(%s, %s, %s); %s" % (
2236 self.result(),
2237 self.start.py_result(),
2238 self.stop.py_result(),
2239 self.step.py_result(),
2240 code.error_goto_if_null(self.result(), self.pos)))
2241 code.put_gotref(self.py_result())
2244 class CallNode(NewTempExprNode):
2245 def analyse_as_type_constructor(self, env):
2246 type = self.function.analyse_as_type(env)
2247 if type and type.is_struct_or_union:
2248 args, kwds = self.explicit_args_kwds()
2249 items = []
2250 for arg, member in zip(args, type.scope.var_entries):
2251 items.append(DictItemNode(pos=arg.pos, key=IdentifierStringNode(pos=arg.pos, value=member.name), value=arg))
2252 if kwds:
2253 items += kwds.key_value_pairs
2254 self.key_value_pairs = items
2255 self.__class__ = DictNode
2256 self.analyse_types(env)
2257 self.coerce_to(type, env)
2258 return True
2260 def gil_check(self, env):
2261 func_type = self.function_type()
2262 if func_type.is_pyobject:
2263 self._gil_check(env)
2264 elif not getattr(func_type, 'nogil', False):
2265 self._gil_check(env)
2267 gil_message = "Calling gil-requiring function"
2270 class SimpleCallNode(CallNode):
2271 # Function call without keyword, * or ** args.
2273 # function ExprNode
2274 # args [ExprNode]
2275 # arg_tuple ExprNode or None used internally
2276 # self ExprNode or None used internally
2277 # coerced_self ExprNode or None used internally
2278 # wrapper_call bool used internally
2279 # has_optional_args bool used internally
2281 subexprs = ['self', 'coerced_self', 'function', 'args', 'arg_tuple']
2283 self = None
2284 coerced_self = None
2285 arg_tuple = None
2286 wrapper_call = False
2287 has_optional_args = False
2289 def compile_time_value(self, denv):
2290 function = self.function.compile_time_value(denv)
2291 args = [arg.compile_time_value(denv) for arg in self.args]
2292 try:
2293 return function(*args)
2294 except Exception, e:
2295 self.compile_time_value_error(e)
2297 def analyse_as_type(self, env):
2298 attr = self.function.as_cython_attribute()
2299 if attr == 'pointer':
2300 if len(self.args) != 1:
2301 error(self.args.pos, "only one type allowed.")
2302 else:
2303 type = self.args[0].analyse_as_type(env)
2304 if not type:
2305 error(self.args[0].pos, "Unknown type")
2306 else:
2307 return PyrexTypes.CPtrType(type)
2309 def explicit_args_kwds(self):
2310 return self.args, None
2312 def analyse_types(self, env):
2313 if self.analyse_as_type_constructor(env):
2314 return
2315 function = self.function
2316 function.is_called = 1
2317 self.function.analyse_types(env)
2318 if function.is_attribute and function.entry and function.entry.is_cmethod:
2319 # Take ownership of the object from which the attribute
2320 # was obtained, because we need to pass it as 'self'.
2321 self.self = function.obj
2322 function.obj = CloneNode(self.self)
2323 func_type = self.function_type()
2324 if func_type.is_pyobject:
2325 self.arg_tuple = TupleNode(self.pos, args = self.args)
2326 self.arg_tuple.analyse_types(env)
2327 self.args = None
2328 self.type = py_object_type
2329 self.is_temp = 1
2330 else:
2331 for arg in self.args:
2332 arg.analyse_types(env)
2333 if self.self and func_type.args:
2334 # Coerce 'self' to the type expected by the method.
2335 expected_type = func_type.args[0].type
2336 self.coerced_self = CloneNode(self.self).coerce_to(
2337 expected_type, env)
2338 # Insert coerced 'self' argument into argument list.
2339 self.args.insert(0, self.coerced_self)
2340 self.analyse_c_function_call(env)
2342 def function_type(self):
2343 # Return the type of the function being called, coercing a function
2344 # pointer to a function if necessary.
2345 func_type = self.function.type
2346 if func_type.is_ptr:
2347 func_type = func_type.base_type
2348 return func_type
2350 def analyse_c_function_call(self, env):
2351 func_type = self.function_type()
2352 # Check function type
2353 if not func_type.is_cfunction:
2354 if not func_type.is_error:
2355 error(self.pos, "Calling non-function type '%s'" %
2356 func_type)
2357 self.type = PyrexTypes.error_type
2358 self.result_code = "<error>"
2359 return
2360 # Check no. of args
2361 max_nargs = len(func_type.args)
2362 expected_nargs = max_nargs - func_type.optional_arg_count
2363 actual_nargs = len(self.args)
2364 if actual_nargs < expected_nargs \
2365 or (not func_type.has_varargs and actual_nargs > max_nargs):
2366 expected_str = str(expected_nargs)
2367 if func_type.has_varargs:
2368 expected_str = "at least " + expected_str
2369 elif func_type.optional_arg_count:
2370 if actual_nargs < max_nargs:
2371 expected_str = "at least " + expected_str
2372 else:
2373 expected_str = "at most " + str(max_nargs)
2374 error(self.pos,
2375 "Call with wrong number of arguments (expected %s, got %s)"
2376 % (expected_str, actual_nargs))
2377 self.args = None
2378 self.type = PyrexTypes.error_type
2379 self.result_code = "<error>"
2380 return
2381 if func_type.optional_arg_count and expected_nargs != actual_nargs:
2382 self.has_optional_args = 1
2383 self.is_temp = 1
2384 self.opt_arg_struct = env.allocate_temp(func_type.op_arg_struct.base_type)
2385 env.release_temp(self.opt_arg_struct)
2386 # Coerce arguments
2387 for i in range(min(max_nargs, actual_nargs)):
2388 formal_type = func_type.args[i].type
2389 self.args[i] = self.args[i].coerce_to(formal_type, env)
2390 for i in range(max_nargs, actual_nargs):
2391 if self.args[i].type.is_pyobject:
2392 error(self.args[i].pos,
2393 "Python object cannot be passed as a varargs parameter")
2394 # Calc result type and code fragment
2395 self.type = func_type.return_type
2396 if self.type.is_pyobject:
2397 self.result_ctype = py_object_type
2398 self.is_temp = 1
2399 elif func_type.exception_value is not None \
2400 or func_type.exception_check:
2401 self.is_temp = 1
2402 # C++ exception handler
2403 if func_type.exception_check == '+':
2404 if func_type.exception_value is None:
2405 env.use_utility_code(cpp_exception_utility_code)
2407 def calculate_result_code(self):
2408 return self.c_call_code()
2410 def c_call_code(self):
2411 func_type = self.function_type()
2412 if self.args is None or not func_type.is_cfunction:
2413 return "<error>"
2414 formal_args = func_type.args
2415 arg_list_code = []
2416 args = zip(formal_args, self.args)
2417 max_nargs = len(func_type.args)
2418 expected_nargs = max_nargs - func_type.optional_arg_count
2419 actual_nargs = len(self.args)
2420 for formal_arg, actual_arg in args[:expected_nargs]:
2421 arg_code = actual_arg.result_as(formal_arg.type)
2422 arg_list_code.append(arg_code)
2424 if func_type.is_overridable:
2425 arg_list_code.append(str(int(self.wrapper_call or self.function.entry.is_unbound_cmethod)))
2427 if func_type.optional_arg_count:
2428 if expected_nargs == actual_nargs:
2429 optional_args = 'NULL'
2430 else:
2431 optional_args = "&%s" % self.opt_arg_struct
2432 arg_list_code.append(optional_args)
2434 for actual_arg in self.args[len(formal_args):]:
2435 arg_list_code.append(actual_arg.result())
2436 result = "%s(%s)" % (self.function.result(),
2437 ', '.join(arg_list_code))
2438 # if self.wrapper_call or \
2439 # self.function.entry.is_unbound_cmethod and self.function.entry.type.is_overridable:
2440 # result = "(%s = 1, %s)" % (Naming.skip_dispatch_cname, result)
2441 return result
2443 def generate_result_code(self, code):
2444 func_type = self.function_type()
2445 if func_type.is_pyobject:
2446 arg_code = self.arg_tuple.py_result()
2447 code.putln(
2448 "%s = PyObject_Call(%s, %s, NULL); %s" % (
2449 self.result(),
2450 self.function.py_result(),
2451 arg_code,
2452 code.error_goto_if_null(self.result(), self.pos)))
2453 code.put_gotref(self.py_result())
2454 elif func_type.is_cfunction:
2455 if self.has_optional_args:
2456 actual_nargs = len(self.args)
2457 expected_nargs = len(func_type.args) - func_type.optional_arg_count
2458 code.putln("%s.%s = %s;" % (
2459 self.opt_arg_struct,
2460 Naming.pyrex_prefix + "n",
2461 len(self.args) - expected_nargs))
2462 args = zip(func_type.args, self.args)
2463 for formal_arg, actual_arg in args[expected_nargs:actual_nargs]:
2464 code.putln("%s.%s = %s;" % (
2465 self.opt_arg_struct,
2466 formal_arg.name,
2467 actual_arg.result_as(formal_arg.type)))
2468 exc_checks = []
2469 if self.type.is_pyobject:
2470 exc_checks.append("!%s" % self.result())
2471 else:
2472 exc_val = func_type.exception_value
2473 exc_check = func_type.exception_check
2474 if exc_val is not None:
2475 exc_checks.append("%s == %s" % (self.result(), exc_val))
2476 if exc_check:
2477 exc_checks.append("PyErr_Occurred()")
2478 if self.is_temp or exc_checks:
2479 rhs = self.c_call_code()
2480 if self.result():
2481 lhs = "%s = " % self.result()
2482 if self.is_temp and self.type.is_pyobject:
2483 #return_type = self.type # func_type.return_type
2484 #print "SimpleCallNode.generate_result_code: casting", rhs, \
2485 # "from", return_type, "to pyobject" ###
2486 rhs = typecast(py_object_type, self.type, rhs)
2487 else:
2488 lhs = ""
2489 if func_type.exception_check == '+':
2490 if func_type.exception_value is None:
2491 raise_py_exception = "__Pyx_CppExn2PyErr()"
2492 elif func_type.exception_value.type.is_pyobject:
2493 raise_py_exception = 'PyErr_SetString(%s, "")' % func_type.exception_value.entry.cname
2494 else:
2495 raise_py_exception = '%s(); if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError , "Error converting c++ exception.")' % func_type.exception_value.entry.cname
2496 code.putln(
2497 "try {%s%s;} catch(...) {%s; %s}" % (
2498 lhs,
2499 rhs,
2500 raise_py_exception,
2501 code.error_goto(self.pos)))
2502 else:
2503 if exc_checks:
2504 goto_error = code.error_goto_if(" && ".join(exc_checks), self.pos)
2505 else:
2506 goto_error = ""
2507 code.putln("%s%s; %s" % (lhs, rhs, goto_error))
2508 if self.type.is_pyobject and self.result():
2509 code.put_gotref(self.py_result())
2512 class PythonCapiFunctionNode(ExprNode):
2513 subexprs = []
2514 def __init__(self, pos, name, func_type, utility_code = None):
2515 self.pos = pos
2516 self.name = name
2517 self.type = func_type
2518 self.utility_code = utility_code
2520 def generate_result_code(self, code):
2521 if self.utility_code:
2522 code.globalstate.use_utility_code(self.utility_code)
2524 def calculate_result_code(self):
2525 return self.name
2527 class PythonCapiCallNode(SimpleCallNode):
2528 # Python C-API Function call (only created in transforms)
2530 def __init__(self, pos, function_name, func_type,
2531 utility_code = None, **kwargs):
2532 self.type = func_type.return_type
2533 self.result_ctype = self.type
2534 self.function = PythonCapiFunctionNode(
2535 pos, function_name, func_type,
2536 utility_code = utility_code)
2537 # call this last so that we can override the constructed
2538 # attributes above with explicit keyword arguments if required
2539 SimpleCallNode.__init__(self, pos, **kwargs)
2542 class GeneralCallNode(CallNode):
2543 # General Python function call, including keyword,
2544 # * and ** arguments.
2546 # function ExprNode
2547 # positional_args ExprNode Tuple of positional arguments
2548 # keyword_args ExprNode or None Dict of keyword arguments
2549 # starstar_arg ExprNode or None Dict of extra keyword args
2551 subexprs = ['function', 'positional_args', 'keyword_args', 'starstar_arg']
2553 gil_check = CallNode._gil_check
2555 def compile_time_value(self, denv):
2556 function = self.function.compile_time_value(denv)
2557 positional_args = self.positional_args.compile_time_value(denv)
2558 keyword_args = self.keyword_args.compile_time_value(denv)
2559 starstar_arg = self.starstar_arg.compile_time_value(denv)
2560 try:
2561 keyword_args.update(starstar_arg)
2562 return function(*positional_args, **keyword_args)
2563 except Exception, e:
2564 self.compile_time_value_error(e)
2566 def explicit_args_kwds(self):
2567 if self.starstar_arg or not isinstance(self.positional_args, TupleNode):
2568 raise PostParseError(self.pos,
2569 'Compile-time keyword arguments must be explicit.')
2570 return self.positional_args.args, self.keyword_args
2572 def analyse_types(self, env):
2573 if self.analyse_as_type_constructor(env):
2574 return
2575 self.function.analyse_types(env)
2576 self.positional_args.analyse_types(env)
2577 if self.keyword_args:
2578 self.keyword_args.analyse_types(env)
2579 if self.starstar_arg:
2580 self.starstar_arg.analyse_types(env)
2581 if not self.function.type.is_pyobject:
2582 if hasattr(self.function, 'entry') and not self.function.entry.as_variable:
2583 error(self.pos, "Keyword arguments not allowed in cdef functions.")
2584 else:
2585 self.function = self.function.coerce_to_pyobject(env)
2586 self.positional_args = \
2587 self.positional_args.coerce_to_pyobject(env)
2588 if self.starstar_arg:
2589 self.starstar_arg = \
2590 self.starstar_arg.coerce_to_pyobject(env)
2591 self.type = py_object_type
2592 self.is_temp = 1
2594 def generate_result_code(self, code):
2595 if self.keyword_args and self.starstar_arg:
2596 code.put_error_if_neg(self.pos,
2597 "PyDict_Update(%s, %s)" % (
2598 self.keyword_args.py_result(),
2599 self.starstar_arg.py_result()))
2600 keyword_code = self.keyword_args.py_result()
2601 elif self.keyword_args:
2602 keyword_code = self.keyword_args.py_result()
2603 elif self.starstar_arg:
2604 keyword_code = self.starstar_arg.py_result()
2605 else:
2606 keyword_code = None
2607 if not keyword_code:
2608 call_code = "PyObject_Call(%s, %s, NULL)" % (
2609 self.function.py_result(),
2610 self.positional_args.py_result())
2611 else:
2612 call_code = "PyEval_CallObjectWithKeywords(%s, %s, %s)" % (
2613 self.function.py_result(),
2614 self.positional_args.py_result(),
2615 keyword_code)
2616 code.putln(
2617 "%s = %s; %s" % (
2618 self.result(),
2619 call_code,
2620 code.error_goto_if_null(self.result(), self.pos)))
2621 code.put_gotref(self.py_result())
2624 class AsTupleNode(NewTempExprNode):
2625 # Convert argument to tuple. Used for normalising
2626 # the * argument of a function call.
2628 # arg ExprNode
2630 subexprs = ['arg']
2632 def calculate_constant_result(self):
2633 self.constant_result = tuple(self.base.constant_result)
2635 def compile_time_value(self, denv):
2636 arg = self.arg.compile_time_value(denv)
2637 try:
2638 return tuple(arg)
2639 except Exception, e:
2640 self.compile_time_value_error(e)
2642 def analyse_types(self, env):
2643 self.arg.analyse_types(env)
2644 self.arg = self.arg.coerce_to_pyobject(env)
2645 self.type = tuple_type
2646 self.is_temp = 1
2648 gil_check = ExprNode._gil_check
2649 gil_message = "Constructing Python tuple"
2651 def generate_result_code(self, code):
2652 code.putln(
2653 "%s = PySequence_Tuple(%s); %s" % (
2654 self.result(),
2655 self.arg.py_result(),
2656 code.error_goto_if_null(self.result(), self.pos)))
2657 code.put_gotref(self.py_result())
2660 class AttributeNode(NewTempExprNode):
2661 # obj.attribute
2663 # obj ExprNode
2664 # attribute string
2665 # needs_none_check boolean Used if obj is an extension type.
2666 # If set to True, it is known that the type is not None.
2668 # Used internally:
2670 # is_py_attr boolean Is a Python getattr operation
2671 # member string C name of struct member
2672 # is_called boolean Function call is being done on result
2673 # entry Entry Symbol table entry of attribute
2675 is_attribute = 1
2676 subexprs = ['obj']
2678 type = PyrexTypes.error_type
2679 entry = None
2680 is_called = 0
2681 needs_none_check = True
2683 def as_cython_attribute(self):
2684 if isinstance(self.obj, NameNode) and self.obj.is_cython_module:
2685 return self.attribute
2687 def coerce_to(self, dst_type, env):
2688 # If coercing to a generic pyobject and this is a cpdef function
2689 # we can create the corresponding attribute
2690 if dst_type is py_object_type:
2691 entry = self.entry
2692 if entry and entry.is_cfunction and entry.as_variable:
2693 # must be a cpdef function
2694 self.is_temp = 1
2695 self.entry = entry.as_variable
2696 self.analyse_as_python_attribute(env)
2697 return self
2698 return ExprNode.coerce_to(self, dst_type, env)
2700 def calculate_constant_result(self):
2701 attr = self.attribute
2702 if attr.startswith("__") and attr.endswith("__"):
2703 return
2704 self.constant_result = getattr(self.obj.constant_result, attr)
2706 def compile_time_value(self, denv):
2707 attr = self.attribute
2708 if attr.startswith("__") and attr.endswith("__"):
2709 self.error("Invalid attribute name '%s' in compile-time expression"
2710 % attr)
2711 return None
2712 obj = self.obj.compile_time_value(denv)
2713 try:
2714 return getattr(obj, attr)
2715 except Exception, e:
2716 self.compile_time_value_error(e)
2718 def analyse_target_declaration(self, env):
2719 pass
2721 def analyse_target_types(self, env):
2722 self.analyse_types(env, target = 1)
2724 def analyse_types(self, env, target = 0):
2725 if self.analyse_as_cimported_attribute(env, target):
2726 return
2727 if not target and self.analyse_as_unbound_cmethod(env):
2728 return
2729 self.analyse_as_ordinary_attribute(env, target)
2731 def analyse_as_cimported_attribute(self, env, target):
2732 # Try to interpret this as a reference to an imported
2733 # C const, type, var or function. If successful, mutates
2734 # this node into a NameNode and returns 1, otherwise
2735 # returns 0.
2736 module_scope = self.obj.analyse_as_module(env)
2737 if module_scope:
2738 entry = module_scope.lookup_here(self.attribute)
2739 if entry and (
2740 entry.is_cglobal or entry.is_cfunction
2741 or entry.is_type or entry.is_const):
2742 self.mutate_into_name_node(env, entry, target)
2743 return 1
2744 return 0
2746 def analyse_as_unbound_cmethod(self, env):
2747 # Try to interpret this as a reference to an unbound
2748 # C method of an extension type. If successful, mutates
2749 # this node into a NameNode and returns 1, otherwise
2750 # returns 0.
2751 type = self.obj.analyse_as_extension_type(env)
2752 if type:
2753 entry = type.scope.lookup_here(self.attribute)
2754 if entry and entry.is_cmethod:
2755 # Create a temporary entry describing the C method
2756 # as an ordinary function.
2757 ubcm_entry = Symtab.Entry(entry.name,
2758 "%s->%s" % (type.vtabptr_cname, entry.cname),
2759 entry.type)
2760 ubcm_entry.is_cfunction = 1
2761 ubcm_entry.func_cname = entry.func_cname
2762 ubcm_entry.is_unbound_cmethod = 1
2763 self.mutate_into_name_node(env, ubcm_entry, None)
2764 return 1
2765 return 0
2767 def analyse_as_type(self, env):
2768 module_scope = self.obj.analyse_as_module(env)
2769 if module_scope:
2770 return module_scope.lookup_type(self.attribute)
2771 return None
2773 def analyse_as_extension_type(self, env):
2774 # Try to interpret this as a reference to an extension type
2775 # in a cimported module. Returns the extension type, or None.
2776 module_scope = self.obj.analyse_as_module(env)
2777 if module_scope:
2778 entry = module_scope.lookup_here(self.attribute)
2779 if entry and entry.is_type and entry.type.is_extension_type:
2780 return entry.type
2781 return None
2783 def analyse_as_module(self, env):
2784 # Try to interpret this as a reference to a cimported module
2785 # in another cimported module. Returns the module scope, or None.
2786 module_scope = self.obj.analyse_as_module(env)
2787 if module_scope:
2788 entry = module_scope.lookup_here(self.attribute)
2789 if entry and entry.as_module:
2790 return entry.as_module
2791 return None
2793 def mutate_into_name_node(self, env, entry, target):
2794 # Mutate this node into a NameNode and complete the
2795 # analyse_types phase.
2796 self.__class__ = NameNode
2797 self.name = self.attribute
2798 self.entry = entry
2799 del self.obj
2800 del self.attribute
2801 if target:
2802 NameNode.analyse_target_types(self, env)
2803 else:
2804 NameNode.analyse_rvalue_entry(self, env)
2806 def analyse_as_ordinary_attribute(self, env, target):
2807 self.obj.analyse_types(env)
2808 self.analyse_attribute(env)
2809 if self.entry and self.entry.is_cmethod and not self.is_called:
2810 # error(self.pos, "C method can only be called")
2811 pass
2812 ## Reference to C array turns into pointer to first element.
2813 #while self.type.is_array:
2814 # self.type = self.type.element_ptr_type()
2815 if self.is_py_attr:
2816 if not target:
2817 self.is_temp = 1
2818 self.result_ctype = py_object_type
2820 def analyse_attribute(self, env):
2821 # Look up attribute and set self.type and self.member.
2822 self.is_py_attr = 0
2823 self.member = self.attribute
2824 if self.obj.type.is_string:
2825 self.obj = self.obj.coerce_to_pyobject(env)
2826 obj_type = self.obj.type
2827 if obj_type.is_ptr or obj_type.is_array:
2828 obj_type = obj_type.base_type
2829 self.op = "->"
2830 elif obj_type.is_extension_type:
2831 self.op = "->"
2832 else:
2833 self.op = "."
2834 if obj_type.has_attributes:
2835 entry = None
2836 if obj_type.attributes_known():
2837 entry = obj_type.scope.lookup_here(self.attribute)
2838 if entry and entry.is_member:
2839 entry = None
2840 else:
2841 error(self.pos,
2842 "Cannot select attribute of incomplete type '%s'"
2843 % obj_type)
2844 self.type = PyrexTypes.error_type
2845 return
2846 self.entry = entry
2847 if entry:
2848 if obj_type.is_extension_type and entry.name == "__weakref__":
2849 error(self.pos, "Illegal use of special attribute __weakref__")
2850 # methods need the normal attribute lookup
2851 # because they do not have struct entries
2852 if entry.is_variable or entry.is_cmethod:
2853 self.type = entry.type
2854 self.member = entry.cname
2855 return
2856 else:
2857 # If it's not a variable or C method, it must be a Python
2858 # method of an extension type, so we treat it like a Python
2859 # attribute.
2860 pass
2861 # If we get here, the base object is not a struct/union/extension
2862 # type, or it is an extension type and the attribute is either not
2863 # declared or is declared as a Python method. Treat it as a Python
2864 # attribute reference.
2865 self.analyse_as_python_attribute(env)
2867 def analyse_as_python_attribute(self, env):
2868 obj_type = self.obj.type
2869 self.member = self.attribute
2870 if obj_type.is_pyobject:
2871 self.type = py_object_type
2872 self.is_py_attr = 1
2873 else:
2874 if not obj_type.is_error:
2875 error(self.pos,
2876 "Object of type '%s' has no attribute '%s'" %
2877 (obj_type, self.attribute))
2879 def gil_check(self, env):
2880 if self.is_py_attr:
2881 self._gil_check(env)
2883 gil_message = "Accessing Python attribute"
2885 def is_simple(self):
2886 if self.obj:
2887 return self.result_in_temp() or self.obj.is_simple()
2888 else:
2889 return NameNode.is_simple(self)
2891 def is_lvalue(self):
2892 if self.obj:
2893 return 1
2894 else:
2895 return NameNode.is_lvalue(self)
2897 def is_ephemeral(self):
2898 if self.obj:
2899 return self.obj.is_ephemeral()
2900 else:
2901 return NameNode.is_ephemeral(self)
2903 def calculate_result_code(self):
2904 #print "AttributeNode.calculate_result_code:", self.member ###
2905 #print "...obj node =", self.obj, "code", self.obj.result() ###
2906 #print "...obj type", self.obj.type, "ctype", self.obj.ctype() ###
2907 obj = self.obj
2908 obj_code = obj.result_as(obj.type)
2909 #print "...obj_code =", obj_code ###
2910 if self.entry and self.entry.is_cmethod:
2911 if obj.type.is_extension_type:
2912 return "((struct %s *)%s%s%s)->%s" % (
2913 obj.type.vtabstruct_cname, obj_code, self.op,
2914 obj.type.vtabslot_cname, self.member)
2915 else:
2916 return self.member
2917 else:
2918 return "%s%s%s" % (obj_code, self.op, self.member)
2920 def generate_result_code(self, code):
2921 interned_attr_cname = code.intern_identifier(self.attribute)
2922 if self.is_py_attr:
2923 code.putln(
2924 '%s = PyObject_GetAttr(%s, %s); %s' % (
2925 self.result(),
2926 self.obj.py_result(),
2927 interned_attr_cname,
2928 code.error_goto_if_null(self.result(), self.pos)))
2929 code.put_gotref(self.py_result())
2930 else:
2931 # result_code contains what is needed, but we may need to insert
2932 # a check and raise an exception
2933 if (self.obj.type.is_extension_type
2934 and self.needs_none_check
2935 and code.globalstate.directives['nonecheck']):
2936 self.put_nonecheck(code)
2938 def generate_assignment_code(self, rhs, code):
2939 interned_attr_cname = code.intern_identifier(self.attribute)
2940 self.obj.generate_evaluation_code(code)
2941 if self.is_py_attr:
2942 code.put_error_if_neg(self.pos,
2943 'PyObject_SetAttr(%s, %s, %s)' % (
2944 self.obj.py_result(),
2945 interned_attr_cname,
2946 rhs.py_result()))
2947 rhs.generate_disposal_code(code)
2948 rhs.free_temps(code)
2949 else:
2950 if (self.obj.type.is_extension_type
2951 and self.needs_none_check
2952 and code.globalstate.directives['nonecheck']):
2953 self.put_nonecheck(code)
2955 select_code = self.result()
2956 if self.type.is_pyobject:
2957 rhs.make_owned_reference(code)
2958 code.put_giveref(rhs.py_result())
2959 code.put_gotref(select_code)
2960 code.put_decref(select_code, self.ctype())
2961 code.putln(
2962 "%s = %s;" % (
2963 select_code,
2964 rhs.result_as(self.ctype())))
2965 #rhs.result()))
2966 rhs.generate_post_assignment_code(code)
2967 rhs.free_temps(code)
2968 self.obj.generate_disposal_code(code)
2969 self.obj.free_temps(code)
2971 def generate_deletion_code(self, code):
2972 interned_attr_cname = code.intern_identifier(self.attribute)
2973 self.obj.generate_evaluation_code(code)
2974 if self.is_py_attr:
2975 code.put_error_if_neg(self.pos,
2976 'PyObject_DelAttr(%s, %s)' % (
2977 self.obj.py_result(),
2978 interned_attr_cname))
2979 else:
2980 error(self.pos, "Cannot delete C attribute of extension type")
2981 self.obj.generate_disposal_code(code)
2982 self.obj.free_temps(code)
2984 def annotate(self, code):
2985 if self.is_py_attr:
2986 code.annotate(self.pos, AnnotationItem('py_attr', 'python attribute', size=len(self.attribute)))
2987 else:
2988 code.annotate(self.pos, AnnotationItem('c_attr', 'c attribute', size=len(self.attribute)))
2990 def put_nonecheck(self, code):
2991 code.globalstate.use_utility_code(raise_noneattr_error_utility_code)
2992 code.putln("if (%s) {" % code.unlikely("%s == Py_None") % self.obj.result_as(PyrexTypes.py_object_type))
2993 code.putln("__Pyx_RaiseNoneAttributeError(\"%s\");" % self.attribute.encode("UTF-8")) # todo: fix encoding
2994 code.putln(code.error_goto(self.pos))
2995 code.putln("}")
2998 #-------------------------------------------------------------------
3000 # Constructor nodes
3002 #-------------------------------------------------------------------
3004 class SequenceNode(NewTempExprNode):
3005 # Base class for list and tuple constructor nodes.
3006 # Contains common code for performing sequence unpacking.
3008 # args [ExprNode]
3009 # iterator ExprNode
3010 # unpacked_items [ExprNode] or None
3011 # coerced_unpacked_items [ExprNode] or None
3013 subexprs = ['args']
3015 is_sequence_constructor = 1
3016 unpacked_items = None
3018 def compile_time_value_list(self, denv):
3019 return [arg.compile_time_value(denv) for arg in self.args]
3021 def analyse_target_declaration(self, env):
3022 for arg in self.args:
3023 arg.analyse_target_declaration(env)
3025 def analyse_types(self, env, skip_children=False):
3026 for i in range(len(self.args)):
3027 arg = self.args[i]
3028 if not skip_children: arg.analyse_types(env)
3029 self.args[i] = arg.coerce_to_pyobject(env)
3030 self.type = py_object_type
3031 self.is_temp = 1
3033 def analyse_target_types(self, env):
3034 self.iterator = PyTempNode(self.pos, env)
3035 self.unpacked_items = []
3036 self.coerced_unpacked_items = []
3037 for arg in self.args:
3038 arg.analyse_target_types(env)
3039 unpacked_item = PyTempNode(self.pos, env)
3040 coerced_unpacked_item = unpacked_item.coerce_to(arg.type, env)
3041 self.unpacked_items.append(unpacked_item)
3042 self.coerced_unpacked_items.append(coerced_unpacked_item)
3043 self.type = py_object_type
3044 env.use_utility_code(unpacking_utility_code)
3046 def allocate_target_temps(self, env, rhs):
3047 self.iterator.allocate_temps(env)
3048 for arg, node in zip(self.args, self.coerced_unpacked_items):
3049 node.allocate_temps(env)
3050 arg.allocate_target_temps(env, None)
3051 #arg.release_target_temp(env)
3052 #node.release_temp(env)
3053 if rhs:
3054 rhs.release_temp(env)
3055 self.iterator.release_temp(env)
3056 for node in self.coerced_unpacked_items:
3057 node.release_temp(env)
3059 # def release_target_temp(self, env):
3060 # #for arg in self.args:
3061 # # arg.release_target_temp(env)
3062 # #for node in self.coerced_unpacked_items:
3063 # # node.release_temp(env)
3064 # self.iterator.release_temp(env)
3066 def generate_result_code(self, code):
3067 self.generate_operation_code(code)
3069 def generate_assignment_code(self, rhs, code):
3070 # Need to work around the fact that generate_evaluation_code
3071 # allocates the temps in a rather hacky way -- the assignment
3072 # is evaluated twice, within each if-block.
3074 if rhs.type is tuple_type:
3075 tuple_check = "likely(%s != Py_None)"
3076 else:
3077 tuple_check = "PyTuple_CheckExact(%s)"
3078 code.putln(
3079 "if (%s && likely(PyTuple_GET_SIZE(%s) == %s)) {" % (
3080 tuple_check % rhs.py_result(),
3081 rhs.py_result(),
3082 len(self.args)))
3083 code.putln("PyObject* tuple = %s;" % rhs.py_result())
3084 for i in range(len(self.args)):
3085 item = self.unpacked_items[i]
3086 code.put(
3087 "%s = PyTuple_GET_ITEM(tuple, %s); " % (
3088 item.result(),
3089 i))
3090 code.put_incref(item.result(), item.ctype())
3091 value_node = self.coerced_unpacked_items[i]
3092 value_node.generate_evaluation_code(code)
3093 rhs.generate_disposal_code(code)
3095 for i in range(len(self.args)):
3096 self.args[i].generate_assignment_code(
3097 self.coerced_unpacked_items[i], code)
3099 code.putln("} else {")
3101 if rhs.type is tuple_type:
3102 code.globalstate.use_utility_code(tuple_unpacking_error_code)
3103 code.putln("__Pyx_UnpackTupleError(%s, %s);" % (
3104 rhs.py_result(), len(self.args)))
3105 code.putln(code.error_goto(self.pos))
3106 else:
3107 code.putln(
3108 "%s = PyObject_GetIter(%s); %s" % (
3109 self.iterator.result(),
3110 rhs.py_result(),
3111 code.error_goto_if_null(self.iterator.result(), self.pos)))
3112 code.put_gotref(self.iterator.py_result())
3113 rhs.generate_disposal_code(code)
3114 for i in range(len(self.args)):
3115 item = self.unpacked_items[i]
3116 unpack_code = "__Pyx_UnpackItem(%s, %d)" % (
3117 self.iterator.py_result(), i)
3118 code.putln(
3119 "%s = %s; %s" % (
3120 item.result(),
3121 typecast(item.ctype(), py_object_type, unpack_code),
3122 code.error_goto_if_null(item.result(), self.pos)))
3123 code.put_gotref(item.py_result())
3124 value_node = self.coerced_unpacked_items[i]
3125 value_node.generate_evaluation_code(code)
3126 code.put_error_if_neg(self.pos,
3127 "__Pyx_EndUnpack(%s)" % (
3128 self.iterator.py_result()))
3129 if debug_disposal_code:
3130 print("UnpackNode.generate_assignment_code:")
3131 print("...generating disposal code for %s" % self.iterator)
3132 self.iterator.generate_disposal_code(code)
3133 self.iterator.free_temps(code)
3135 for i in range(len(self.args)):
3136 self.args[i].generate_assignment_code(
3137 self.coerced_unpacked_items[i], code)
3139 code.putln("}")
3140 rhs.free_temps(code)
3142 def annotate(self, code):
3143 for arg in self.args:
3144 arg.annotate(code)
3145 if self.unpacked_items:
3146 for arg in self.unpacked_items:
3147 arg.annotate(code)
3148 for arg in self.coerced_unpacked_items:
3149 arg.annotate(code)
3152 class TupleNode(SequenceNode):
3153 # Tuple constructor.
3155 gil_message = "Constructing Python tuple"
3157 def analyse_types(self, env, skip_children=False):
3158 if len(self.args) == 0:
3159 self.is_temp = 0
3160 self.is_literal = 1
3161 else:
3162 SequenceNode.analyse_types(self, env, skip_children)
3163 self.type = tuple_type
3165 def calculate_result_code(self):
3166 if len(self.args) > 0:
3167 error(self.pos, "Positive length tuples must be constructed.")
3168 else:
3169 return Naming.empty_tuple
3171 def calculate_constant_result(self):
3172 self.constant_result = tuple([
3173 arg.constant_result for arg in self.args])
3175 def compile_time_value(self, denv):
3176 values = self.compile_time_value_list(denv)
3177 try:
3178 return tuple(values)
3179 except Exception, e:
3180 self.compile_time_value_error(e)
3182 def generate_operation_code(self, code):
3183 if len(self.args) == 0:
3184 # result_code is Naming.empty_tuple
3185 return
3186 code.putln(
3187 "%s = PyTuple_New(%s); %s" % (
3188 self.result(),
3189 len(self.args),
3190 code.error_goto_if_null(self.result(), self.pos)))
3191 code.put_gotref(self.py_result())
3192 for i in range(len(self.args)):
3193 arg = self.args[i]
3194 if not arg.result_in_temp():
3195 code.put_incref(arg.result(), arg.ctype())
3196 code.putln(
3197 "PyTuple_SET_ITEM(%s, %s, %s);" % (
3198 self.result(),
3199 i,
3200 arg.py_result()))
3201 code.put_giveref(arg.py_result())
3203 def generate_subexpr_disposal_code(self, code):
3204 # We call generate_post_assignment_code here instead
3205 # of generate_disposal_code, because values were stored
3206 # in the tuple using a reference-stealing operation.
3207 for arg in self.args:
3208 arg.generate_post_assignment_code(code)
3209 # Should NOT call free_temps -- this is invoked by the default
3210 # generate_evaluation_code which will do that.
3213 class ListNode(SequenceNode):
3214 # List constructor.
3216 # obj_conversion_errors [PyrexError] used internally
3217 # orignial_args [ExprNode] used internally
3219 gil_message = "Constructing Python list"
3221 def analyse_expressions(self, env):
3222 SequenceNode.analyse_expressions(self, env)
3223 self.coerce_to_pyobject(env)
3225 def analyse_types(self, env):
3226 hold_errors()
3227 self.original_args = list(self.args)
3228 SequenceNode.analyse_types(self, env)
3229 self.type = list_type
3230 self.obj_conversion_errors = held_errors()
3231 release_errors(ignore=True)
3233 def coerce_to(self, dst_type, env):
3234 if dst_type.is_pyobject:
3235 for err in self.obj_conversion_errors:
3236 report_error(err)
3237 self.obj_conversion_errors = []
3238 if not self.type.subtype_of(dst_type):
3239 error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
3240 elif dst_type.is_ptr:
3241 base_type = dst_type.base_type
3242 self.type = PyrexTypes.CArrayType(base_type, len(self.args))
3243 for i in range(len(self.original_args)):
3244 arg = self.args[i]
3245 if isinstance(arg, CoerceToPyTypeNode):
3246 arg = arg.arg
3247 self.args[i] = arg.coerce_to(base_type, env)
3248 elif dst_type.is_struct:
3249 if len(self.args) > len(dst_type.scope.var_entries):
3250 error(self.pos, "Too may members for '%s'" % dst_type)
3251 else:
3252 if len(self.args) < len(dst_type.scope.var_entries):
3253 warning(self.pos, "Too few members for '%s'" % dst_type, 1)
3254 for i, (arg, member) in enumerate(zip(self.original_args, dst_type.scope.var_entries)):
3255 if isinstance(arg, CoerceToPyTypeNode):
3256 arg = arg.arg
3257 self.args[i] = arg.coerce_to(member.type, env)
3258 self.type = dst_type
3259 else:
3260 self.type = error_type
3261 error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
3262 return self
3264 def release_temp(self, env):
3265 if self.type.is_array:
3266 # To be valid C++, we must allocate the memory on the stack
3267 # manually and be sure not to reuse it for something else.
3268 pass
3269 else:
3270 SequenceNode.release_temp(self, env)
3272 def calculate_constant_result(self):
3273 self.constant_result = [
3274 arg.constant_result for arg in self.args]
3276 def compile_time_value(self, denv):
3277 return self.compile_time_value_list(denv)
3279 def generate_operation_code(self, code):
3280 if self.type.is_pyobject:
3281 for err in self.obj_conversion_errors:
3282 report_error(err)
3283 code.putln("%s = PyList_New(%s); %s" %
3284 (self.result(),
3285 len(self.args),
3286 code.error_goto_if_null(self.result(), self.pos)))
3287 code.put_gotref(self.py_result())
3288 for i in range(len(self.args)):
3289 arg = self.args[i]
3290 #if not arg.is_temp:
3291 if not arg.result_in_temp():
3292 code.put_incref(arg.result(), arg.ctype())
3293 code.putln("PyList_SET_ITEM(%s, %s, %s);" %
3294 (self.result(),
3295 i,
3296 arg.py_result()))
3297 code.put_giveref(arg.py_result())
3298 elif self.type.is_array:
3299 for i, arg in enumerate(self.args):
3300 code.putln("%s[%s] = %s;" % (
3301 self.result(),
3302 i,
3303 arg.result()))
3304 elif self.type.is_struct:
3305 for arg, member in zip(self.args, self.type.scope.var_entries):
3306 code.putln("%s.%s = %s;" % (
3307 self.result(),
3308 member.cname,
3309 arg.result()))
3310 else:
3311 raise InternalError("List type never specified")
3313 def generate_subexpr_disposal_code(self, code):
3314 # We call generate_post_assignment_code here instead
3315 # of generate_disposal_code, because values were stored
3316 # in the list using a reference-stealing operation.
3317 for arg in self.args:
3318 arg.generate_post_assignment_code(code)
3319 # Should NOT call free_temps -- this is invoked by the default
3320 # generate_evaluation_code which will do that.
3323 class ComprehensionNode(NewTempExprNode):
3324 subexprs = ["target"]
3325 child_attrs = ["loop", "append"]
3327 def analyse_types(self, env):
3328 self.target.analyse_expressions(env)
3329 self.type = self.target.type
3330 self.append.target = self # this is a CloneNode used in the PyList_Append in the inner loop
3331 self.loop.analyse_declarations(env)
3333 def allocate_temps(self, env, result = None):
3334 if debug_temp_alloc:
3335 print("%s Allocating temps" % self)
3336 self.allocate_temp(env, result)
3337 # call loop.analyse_expressions() now to make sure temps get
3338 # allocated at the right time
3339 self.loop.analyse_expressions(env)
3341 def calculate_result_code(self):
3342 return self.target.result()
3344 def generate_result_code(self, code):
3345 self.generate_operation_code(code)
3347 def generate_operation_code(self, code):
3348 self.loop.generate_execution_code(code)
3350 def annotate(self, code):
3351 self.loop.annotate(code)
3354 class ComprehensionAppendNode(NewTempExprNode):
3355 # Need to be careful to avoid infinite recursion:
3356 # target must not be in child_attrs/subexprs
3357 subexprs = ['expr']
3359 def analyse_types(self, env):
3360 self.expr.analyse_types(env)
3361 if not self.expr.type.is_pyobject:
3362 self.expr = self.expr.coerce_to_pyobject(env)
3363 self.type = PyrexTypes.c_int_type
3364 self.is_temp = 1
3366 def generate_result_code(self, code):
3367 if self.target.type is list_type:
3368 function = "PyList_Append"
3369 elif self.target.type is set_type:
3370 function = "PySet_Add"
3371 else:
3372 raise InternalError(
3373 "Invalid type for comprehension node: %s" % self.target.type)
3375 code.putln("%s = %s(%s, (PyObject*)%s); %s" %
3376 (self.result(),
3377 function,
3378 self.target.result(),
3379 self.expr.result(),
3380 code.error_goto_if(self.result(), self.pos)))
3382 class DictComprehensionAppendNode(ComprehensionAppendNode):
3383 subexprs = ['key_expr', 'value_expr']
3385 def analyse_types(self, env):
3386 self.key_expr.analyse_types(env)
3387 if not self.key_expr.type.is_pyobject:
3388 self.key_expr = self.key_expr.coerce_to_pyobject(env)
3389 self.value_expr.analyse_types(env)
3390 if not self.value_expr.type.is_pyobject:
3391 self.value_expr = self.value_expr.coerce_to_pyobject(env)
3392 self.type = PyrexTypes.c_int_type
3393 self.is_temp = 1
3395 def generate_result_code(self, code):
3396 code.putln("%s = PyDict_SetItem(%s, (PyObject*)%s, (PyObject*)%s); %s" %
3397 (self.result(),
3398 self.target.result(),
3399 self.key_expr.result(),
3400 self.value_expr.result(),
3401 code.error_goto_if(self.result(), self.pos)))
3404 class SetNode(NewTempExprNode):
3405 # Set constructor.
3407 subexprs = ['args']
3409 gil_message = "Constructing Python set"
3411 def analyse_types(self, env):
3412 for i in range(len(self.args)):
3413 arg = self.args[i]
3414 arg.analyse_types(env)
3415 self.args[i] = arg.coerce_to_pyobject(env)
3416 self.type = set_type
3417 self.is_temp = 1
3419 def calculate_constant_result(self):
3420 self.constant_result = set([
3421 arg.constant_result for arg in self.args])
3423 def compile_time_value(self, denv):
3424 values = [arg.compile_time_value(denv) for arg in self.args]
3425 try:
3426 return set(values)
3427 except Exception, e:
3428 self.compile_time_value_error(e)
3430 def generate_evaluation_code(self, code):
3431 code.globalstate.use_utility_code(Builtin.py23_set_utility_code)
3432 self.allocate_temp_result(code)
3433 code.putln(
3434 "%s = PySet_New(0); %s" % (
3435 self.result(),
3436 code.error_goto_if_null(self.result(), self.pos)))
3437 code.put_gotref(self.py_result())
3438 for arg in self.args:
3439 arg.generate_evaluation_code(code)
3440 code.putln(
3441 code.error_goto_if_neg(
3442 "PySet_Add(%s, %s)" % (self.result(), arg.py_result()),
3443 self.pos))
3444 arg.generate_disposal_code(code)
3445 arg.free_temps(code)
3448 class DictNode(NewTempExprNode):
3449 # Dictionary constructor.
3451 # key_value_pairs [DictItemNode]
3453 # obj_conversion_errors [PyrexError] used internally
3455 subexprs = ['key_value_pairs']
3457 def calculate_constant_result(self):
3458 self.constant_result = dict([
3459 item.constant_result for item in self.key_value_pairs])
3461 def compile_time_value(self, denv):
3462 pairs = [(item.key.compile_time_value(denv), item.value.compile_time_value(denv))
3463 for item in self.key_value_pairs]
3464 try:
3465 return dict(pairs)
3466 except Exception, e:
3467 self.compile_time_value_error(e)
3469 def analyse_types(self, env):
3470 hold_errors()
3471 self.type = dict_type
3472 for item in self.key_value_pairs:
3473 item.analyse_types(env)
3474 self.obj_conversion_errors = held_errors()
3475 release_errors(ignore=True)
3476 self.is_temp = 1
3478 def coerce_to(self, dst_type, env):
3479 if dst_type.is_pyobject:
3480 self.release_errors()
3481 if not self.type.subtype_of(dst_type):
3482 error(self.pos, "Cannot interpret dict as type '%s'" % dst_type)
3483 elif dst_type.is_struct_or_union:
3484 self.type = dst_type
3485 if not dst_type.is_struct and len(self.key_value_pairs) != 1:
3486 error(self.pos, "Exactly one field must be specified to convert to union '%s'" % dst_type)
3487 elif dst_type.is_struct and len(self.key_value_pairs) < len(dst_type.scope.var_entries):
3488 warning(self.pos, "Not all members given for struct '%s'" % dst_type, 1)
3489 for item in self.key_value_pairs:
3490 if isinstance(item.key, CoerceToPyTypeNode):
3491 item.key = item.key.arg
3492 if not isinstance(item.key, (StringNode, IdentifierStringNode)):
3493 error(item.key.pos, "Invalid struct field identifier")
3494 item.key = IdentifierStringNode(item.key.pos, value="<error>")
3495 else:
3496 member = dst_type.scope.lookup_here(item.key.value)
3497 if not member:
3498 error(item.key.pos, "struct '%s' has no field '%s'" % (dst_type, item.key.value))
3499 else:
3500 value = item.value
3501 if isinstance(value, CoerceToPyTypeNode):
3502 value = value.arg
3503 item.value = value.coerce_to(member.type, env)
3504 else:
3505 self.type = error_type
3506 error(self.pos, "Cannot interpret dict as type '%s'" % dst_type)
3507 return self
3509 def release_errors(self):
3510 for err in self.obj_conversion_errors:
3511 report_error(err)
3512 self.obj_conversion_errors = []
3514 gil_message = "Constructing Python dict"
3516 def generate_evaluation_code(self, code):
3517 # Custom method used here because key-value
3518 # pairs are evaluated and used one at a time.
3519 code.mark_pos(self.pos)
3520 self.allocate_temp_result(code)
3521 if self.type.is_pyobject:
3522 self.release_errors()
3523 code.putln(
3524 "%s = PyDict_New(); %s" % (
3525 self.result(),
3526 code.error_goto_if_null(self.result(), self.pos)))
3527 code.put_gotref(self.py_result())
3528 for item in self.key_value_pairs:
3529 item.generate_evaluation_code(code)
3530 if self.type.is_pyobject:
3531 code.put_error_if_neg(self.pos,
3532 "PyDict_SetItem(%s, %s, %s)" % (
3533 self.result(),
3534 item.key.py_result(),
3535 item.value.py_result()))
3536 else:
3537 code.putln("%s.%s = %s;" % (
3538 self.result(),
3539 item.key.value,
3540 item.value.result()))
3541 item.generate_disposal_code(code)
3542 item.free_temps(code)
3544 def annotate(self, code):
3545 for item in self.key_value_pairs:
3546 item.annotate(code)
3548 class DictItemNode(NewTempExprNode):
3549 # Represents a single item in a DictNode
3551 # key ExprNode
3552 # value ExprNode
3553 subexprs = ['key', 'value']
3555 gil_check = None # handled by DictNode
3557 def calculate_constant_result(self):
3558 self.constant_result = (
3559 self.key.constant_result, self.value.constant_result)
3561 def analyse_types(self, env):
3562 self.key.analyse_types(env)
3563 self.value.analyse_types(env)
3564 self.key = self.key.coerce_to_pyobject(env)
3565 self.value = self.value.coerce_to_pyobject(env)
3567 def generate_evaluation_code(self, code):
3568 self.key.generate_evaluation_code(code)
3569 self.value.generate_evaluation_code(code)
3571 def generate_disposal_code(self, code):
3572 self.key.generate_disposal_code(code)
3573 self.value.generate_disposal_code(code)
3575 def free_temps(self, code):
3576 self.key.free_temps(code)
3577 self.value.free_temps(code)
3579 def __iter__(self):
3580 return iter([self.key, self.value])
3583 class ClassNode(NewTempExprNode):
3584 # Helper class used in the implementation of Python
3585 # class definitions. Constructs a class object given
3586 # a name, tuple of bases and class dictionary.
3588 # name EncodedString Name of the class
3589 # bases ExprNode Base class tuple
3590 # dict ExprNode Class dict (not owned by this node)
3591 # doc ExprNode or None Doc string
3592 # module_name string Name of defining module
3594 subexprs = ['bases', 'doc']
3596 def analyse_types(self, env):
3597 self.bases.analyse_types(env)
3598 if self.doc:
3599 self.doc.analyse_types(env)
3600 self.doc = self.doc.coerce_to_pyobject(env)
3601 self.module_name = env.global_scope().qualified_name
3602 self.type = py_object_type
3603 self.is_temp = 1
3604 env.use_utility_code(create_class_utility_code);
3606 gil_message = "Constructing Python class"
3608 def generate_result_code(self, code):
3609 cname = code.intern_identifier(self.name)
3610 if self.doc:
3611 code.put_error_if_neg(self.pos,
3612 'PyDict_SetItemString(%s, "__doc__", %s)' % (
3613 self.dict.py_result(),
3614 self.doc.py_result()))
3615 code.putln(
3616 '%s = __Pyx_CreateClass(%s, %s, %s, "%s"); %s' % (
3617 self.result(),
3618 self.bases.py_result(),
3619 self.dict.py_result(),
3620 cname,
3621 self.module_name,
3622 code.error_goto_if_null(self.result(), self.pos)))
3623 code.put_gotref(self.py_result())
3626 class UnboundMethodNode(NewTempExprNode):
3627 # Helper class used in the implementation of Python
3628 # class definitions. Constructs an unbound method
3629 # object from a class and a function.
3631 # function ExprNode Function object
3633 subexprs = ['function']
3635 def analyse_types(self, env):
3636 self.function.analyse_types(env)
3637 self.type = py_object_type
3638 self.is_temp = 1
3640 gil_message = "Constructing an unbound method"
3642 def generate_result_code(self, code):
3643 class_cname = code.pyclass_stack[-1].classobj.result()
3644 code.putln(
3645 "%s = PyMethod_New(%s, 0, %s); %s" % (
3646 self.result(),
3647 self.function.py_result(),
3648 class_cname,
3649 code.error_goto_if_null(self.result(), self.pos)))
3650 code.put_gotref(self.py_result())
3652 class PyCFunctionNode(AtomicNewTempExprNode):
3653 # Helper class used in the implementation of Python
3654 # class definitions. Constructs a PyCFunction object
3655 # from a PyMethodDef struct.
3657 # pymethdef_cname string PyMethodDef structure
3659 def analyse_types(self, env):
3660 self.type = py_object_type
3661 self.is_temp = 1
3663 gil_message = "Constructing Python function"
3665 def generate_result_code(self, code):
3666 code.putln(
3667 "%s = PyCFunction_New(&%s, 0); %s" % (
3668 self.result(),
3669 self.pymethdef_cname,
3670 code.error_goto_if_null(self.result(), self.pos)))
3671 code.put_gotref(self.py_result())
3673 #-------------------------------------------------------------------
3675 # Unary operator nodes
3677 #-------------------------------------------------------------------
3679 compile_time_unary_operators = {
3680 'not': operator.not_,
3681 '~': operator.inv,
3682 '-': operator.neg,
3683 '+': operator.pos,
3686 class UnopNode(NewTempExprNode):
3687 # operator string
3688 # operand ExprNode
3690 # Processing during analyse_expressions phase:
3692 # analyse_c_operation
3693 # Called when the operand is not a pyobject.
3694 # - Check operand type and coerce if needed.
3695 # - Determine result type and result code fragment.
3696 # - Allocate temporary for result if needed.
3698 subexprs = ['operand']
3700 def calculate_constant_result(self):
3701 func = compile_time_unary_operators[self.operator]
3702 self.constant_result = func(self.operand.constant_result)
3704 def compile_time_value(self, denv):
3705 func = compile_time_unary_operators.get(self.operator)
3706 if not func:
3707 error(self.pos,
3708 "Unary '%s' not supported in compile-time expression"
3709 % self.operator)
3710 operand = self.operand.compile_time_value(denv)
3711 try:
3712 return func(operand)
3713 except Exception, e:
3714 self.compile_time_value_error(e)
3716 def analyse_types(self, env):
3717 self.operand.analyse_types(env)
3718 if self.is_py_operation():
3719 self.coerce_operand_to_pyobject(env)
3720 self.type = py_object_type
3721 self.is_temp = 1
3722 else:
3723 self.analyse_c_operation(env)
3725 def check_const(self):
3726 self.operand.check_const()
3728 def is_py_operation(self):
3729 return self.operand.type.is_pyobject
3731 def gil_check(self, env):
3732 if self.is_py_operation():
3733 self._gil_check(env)
3735 def coerce_operand_to_pyobject(self, env):
3736 self.operand = self.operand.coerce_to_pyobject(env)
3738 def generate_result_code(self, code):
3739 if self.operand.type.is_pyobject:
3740 self.generate_py_operation_code(code)
3741 else:
3742 if self.is_temp:
3743 self.generate_c_operation_code(code)
3745 def generate_py_operation_code(self, code):
3746 function = self.py_operation_function()
3747 code.putln(
3748 "%s = %s(%s); %s" % (
3749 self.result(),
3750 function,
3751 self.operand.py_result(),
3752 code.error_goto_if_null(self.result(), self.pos)))
3753 code.put_gotref(self.py_result())
3755 def type_error(self):
3756 if not self.operand.type.is_error:
3757 error(self.pos, "Invalid operand type for '%s' (%s)" %
3758 (self.operator, self.operand.type))
3759 self.type = PyrexTypes.error_type
3762 class NotNode(NewTempExprNode):
3763 # 'not' operator
3765 # operand ExprNode
3767 def calculate_constant_result(self):
3768 self.constant_result = not self.operand.constant_result
3770 def compile_time_value(self, denv):
3771 operand = self.operand.compile_time_value(denv)
3772 try:
3773 return not operand
3774 except Exception, e:
3775 self.compile_time_value_error(e)
3777 subexprs = ['operand']
3779 def analyse_types(self, env):
3780 self.operand.analyse_types(env)
3781 self.operand = self.operand.coerce_to_boolean(env)
3782 self.type = PyrexTypes.c_bint_type
3784 def calculate_result_code(self):
3785 return "(!%s)" % self.operand.result()
3787 def generate_result_code(self, code):
3788 pass
3791 class UnaryPlusNode(UnopNode):
3792 # unary '+' operator
3794 operator = '+'
3796 def analyse_c_operation(self, env):
3797 self.type = self.operand.type
3799 def py_operation_function(self):
3800 return "PyNumber_Positive"
3802 def calculate_result_code(self):
3803 return self.operand.result()
3806 class UnaryMinusNode(UnopNode):
3807 # unary '-' operator
3809 operator = '-'
3811 def analyse_c_operation(self, env):
3812 if self.operand.type.is_numeric:
3813 self.type = self.operand.type
3814 else:
3815 self.type_error()
3817 def py_operation_function(self):
3818 return "PyNumber_Negative"
3820 def calculate_result_code(self):
3821 return "(-%s)" % self.operand.result()
3824 class TildeNode(UnopNode):
3825 # unary '~' operator
3827 def analyse_c_operation(self, env):
3828 if self.operand.type.is_int:
3829 self.type = self.operand.type
3830 else:
3831 self.type_error()
3833 def py_operation_function(self):
3834 return "PyNumber_Invert"
3836 def calculate_result_code(self):
3837 return "(~%s)" % self.operand.result()
3840 class AmpersandNode(NewTempExprNode):
3841 # The C address-of operator.
3843 # operand ExprNode
3845 subexprs = ['operand']
3847 def analyse_types(self, env):
3848 self.operand.analyse_types(env)
3849 argtype = self.operand.type
3850 if not (argtype.is_cfunction or self.operand.is_lvalue()):
3851 self.error("Taking address of non-lvalue")
3852 return
3853 if argtype.is_pyobject:
3854 self.error("Cannot take address of Python variable")
3855 return
3856 self.type = PyrexTypes.c_ptr_type(argtype)
3858 def check_const(self):
3859 self.operand.check_const_addr()
3861 def error(self, mess):
3862 error(self.pos, mess)
3863 self.type = PyrexTypes.error_type
3864 self.result_code = "<error>"
3866 def calculate_result_code(self):
3867 return "(&%s)" % self.operand.result()
3869 def generate_result_code(self, code):
3870 pass
3873 unop_node_classes = {
3874 "+": UnaryPlusNode,
3875 "-": UnaryMinusNode,
3876 "~": TildeNode,
3879 def unop_node(pos, operator, operand):
3880 # Construct unnop node of appropriate class for
3881 # given operator.
3882 if isinstance(operand, IntNode) and operator == '-':
3883 return IntNode(pos = operand.pos, value = str(-int(operand.value, 0)))
3884 elif isinstance(operand, UnopNode) and operand.operator == operator:
3885 warning(pos, "Python has no increment/decrement operator: %s%sx = %s(%sx) = x" % ((operator,)*4), 5)
3886 return unop_node_classes[operator](pos,
3887 operator = operator,
3888 operand = operand)
3891 class TypecastNode(NewTempExprNode):
3892 # C type cast
3894 # operand ExprNode
3895 # base_type CBaseTypeNode
3896 # declarator CDeclaratorNode
3898 # If used from a transform, one can if wanted specify the attribute
3899 # "type" directly and leave base_type and declarator to None
3901 subexprs = ['operand']
3902 base_type = declarator = type = None
3904 def analyse_types(self, env):
3905 if self.type is None:
3906 base_type = self.base_type.analyse(env)
3907 _, self.type = self.declarator.analyse(base_type, env)
3908 if self.type.is_cfunction:
3909 error(self.pos,
3910 "Cannot cast to a function type")
3911 self.type = PyrexTypes.error_type
3912 self.operand.analyse_types(env)
3913 to_py = self.type.is_pyobject
3914 from_py = self.operand.type.is_pyobject
3915 if from_py and not to_py and self.operand.is_ephemeral() and not self.type.is_numeric:
3916 error(self.pos, "Casting temporary Python object to non-numeric non-Python type")
3917 if to_py and not from_py:
3918 if (self.operand.type.to_py_function and
3919 self.operand.type.create_convert_utility_code(env)):
3920 self.result_ctype = py_object_type
3921 self.operand = self.operand.coerce_to_pyobject(env)
3922 else:
3923 warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.operand.type, self.type))
3924 self.operand = self.operand.coerce_to_simple(env)
3925 elif from_py and not to_py:
3926 if self.type.from_py_function:
3927 self.operand = self.operand.coerce_to(self.type, env)
3928 else:
3929 warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.type, self.operand.type))
3930 elif from_py and to_py:
3931 if self.typecheck and self.type.is_extension_type:
3932 self.operand = PyTypeTestNode(self.operand, self.type, env)
3934 def gil_check(self, env):
3935 if self.type.is_pyobject and self.is_temp:
3936 self._gil_check(env)
3938 def check_const(self):
3939 self.operand.check_const()
3941 def calculate_constant_result(self):
3942 # we usually do not know the result of a type cast at code
3943 # generation time
3944 pass
3946 def calculate_result_code(self):
3947 opnd = self.operand
3948 return self.type.cast_code(opnd.result())
3950 def result_as(self, type):
3951 if self.type.is_pyobject and not self.is_temp:
3952 # Optimise away some unnecessary casting
3953 return self.operand.result_as(type)
3954 else:
3955 return ExprNode.result_as(self, type)
3957 def generate_result_code(self, code):
3958 if self.is_temp:
3959 code.putln(
3960 "%s = (PyObject *)%s;" % (
3961 self.result(),
3962 self.operand.result()))
3963 code.put_incref(self.result(), self.ctype())
3966 class SizeofNode(NewTempExprNode):
3967 # Abstract base class for sizeof(x) expression nodes.
3969 type = PyrexTypes.c_size_t_type
3971 def check_const(self):
3972 pass
3974 def generate_result_code(self, code):
3975 pass
3978 class SizeofTypeNode(SizeofNode):
3979 # C sizeof function applied to a type
3981 # base_type CBaseTypeNode
3982 # declarator CDeclaratorNode
3984 subexprs = []
3985 arg_type = None
3987 def analyse_types(self, env):
3988 # we may have incorrectly interpreted a dotted name as a type rather than an attribute
3989 # this could be better handled by more uniformly treating types as runtime-available objects
3990 if 0 and self.base_type.module_path:
3991 path = self.base_type.module_path
3992 obj = env.lookup(path[0])
3993 if obj.as_module is None:
3994 operand = NameNode(pos=self.pos, name=path[0])
3995 for attr in path[1:]:
3996 operand = AttributeNode(pos=self.pos, obj=operand, attribute=attr)
3997 operand = AttributeNode(pos=self.pos, obj=operand, attribute=self.base_type.name)
3998 self.operand = operand
3999 self.__class__ = SizeofVarNode
4000 self.analyse_types(env)
4001 return
4002 if self.arg_type is None:
4003 base_type = self.base_type.analyse(env)
4004 _, arg_type = self.declarator.analyse(base_type, env)
4005 self.arg_type = arg_type
4006 self.check_type()
4008 def check_type(self):
4009 arg_type = self.arg_type
4010 if arg_type.is_pyobject and not arg_type.is_extension_type:
4011 error(self.pos, "Cannot take sizeof Python object")
4012 elif arg_type.is_void:
4013 error(self.pos, "Cannot take sizeof void")
4014 elif not arg_type.is_complete():
4015 error(self.pos, "Cannot take sizeof incomplete type '%s'" % arg_type)
4017 def calculate_result_code(self):
4018 if self.arg_type.is_extension_type:
4019 # the size of the pointer is boring
4020 # we want the size of the actual struct
4021 arg_code = self.arg_type.declaration_code("", deref=1)
4022 else:
4023 arg_code = self.arg_type.declaration_code("")
4024 return "(sizeof(%s))" % arg_code
4027 class SizeofVarNode(SizeofNode):
4028 # C sizeof function applied to a variable
4030 # operand ExprNode
4032 subexprs = ['operand']
4034 def analyse_types(self, env):
4035 # We may actually be looking at a type rather than a variable...
4036 # If we are, traditional analysis would fail...
4037 operand_as_type = self.operand.analyse_as_type(env)
4038 if operand_as_type:
4039 self.arg_type = operand_as_type
4040 self.__class__ = SizeofTypeNode
4041 self.check_type()
4042 else:
4043 self.operand.analyse_types(env)
4045 def calculate_result_code(self):
4046 return "(sizeof(%s))" % self.operand.result()
4048 def generate_result_code(self, code):
4049 pass
4052 #-------------------------------------------------------------------
4054 # Binary operator nodes
4056 #-------------------------------------------------------------------
4058 def _not_in(x, seq):
4059 return x not in seq
4061 compile_time_binary_operators = {
4062 '<': operator.lt,
4063 '<=': operator.le,
4064 '==': operator.eq,
4065 '!=': operator.ne,
4066 '>=': operator.ge,
4067 '>': operator.gt,
4068 'is': operator.is_,
4069 'is_not': operator.is_not,
4070 '+': operator.add,
4071 '&': operator.and_,
4072 '/': operator.div,
4073 '//': operator.floordiv,
4074 '<<': operator.lshift,
4075 '%': operator.mod,
4076 '*': operator.mul,
4077 '|': operator.or_,
4078 '**': operator.pow,
4079 '>>': operator.rshift,
4080 '-': operator.sub,
4081 #'/': operator.truediv,
4082 '^': operator.xor,
4083 'in': operator.contains,
4084 'not_in': _not_in,
4087 def get_compile_time_binop(node):
4088 func = compile_time_binary_operators.get(node.operator)
4089 if not func:
4090 error(node.pos,
4091 "Binary '%s' not supported in compile-time expression"
4092 % node.operator)
4093 return func
4095 class BinopNode(NewTempExprNode):
4096 # operator string
4097 # operand1 ExprNode
4098 # operand2 ExprNode
4100 # Processing during analyse_expressions phase:
4102 # analyse_c_operation
4103 # Called when neither operand is a pyobject.
4104 # - Check operand types and coerce if needed.
4105 # - Determine result type and result code fragment.
4106 # - Allocate temporary for result if needed.
4108 subexprs = ['operand1', 'operand2']
4110 def calculate_constant_result(self):
4111 func = compile_time_binary_operators[self.operator]
4112 self.constant_result = func(
4113 self.operand1.constant_result,
4114 self.operand2.constant_result)
4116 def compile_time_value(self, denv):
4117 func = get_compile_time_binop(self)
4118 operand1 = self.operand1.compile_time_value(denv)
4119 operand2 = self.operand2.compile_time_value(denv)
4120 try:
4121 return func(operand1, operand2)
4122 except Exception, e:
4123 self.compile_time_value_error(e)
4125 def analyse_types(self, env):
4126 self.operand1.analyse_types(env)
4127 self.operand2.analyse_types(env)
4128 if self.is_py_operation():
4129 self.coerce_operands_to_pyobjects(env)
4130 self.type = py_object_type
4131 self.is_temp = 1
4132 if Options.incref_local_binop and self.operand1.type.is_pyobject:
4133 self.operand1 = self.operand1.coerce_to_temp(env)
4134 else:
4135 self.analyse_c_operation(env)
4137 def is_py_operation(self):
4138 return (self.operand1.type.is_pyobject
4139 or self.operand2.type.is_pyobject)
4141 def gil_check(self, env):
4142 if self.is_py_operation():
4143 self._gil_check(env)
4145 def coerce_operands_to_pyobjects(self, env):
4146 self.operand1 = self.operand1.coerce_to_pyobject(env)
4147 self.operand2 = self.operand2.coerce_to_pyobject(env)
4149 def check_const(self):
4150 self.operand1.check_const()
4151 self.operand2.check_const()
4153 def generate_result_code(self, code):
4154 #print "BinopNode.generate_result_code:", self.operand1, self.operand2 ###
4155 if self.operand1.type.is_pyobject:
4156 function = self.py_operation_function()
4157 if function == "PyNumber_Power":
4158 extra_args = ", Py_None"
4159 else:
4160 extra_args = ""
4161 code.putln(
4162 "%s = %s(%s, %s%s); %s" % (
4163 self.result(),
4164 function,
4165 self.operand1.py_result(),
4166 self.operand2.py_result(),
4167 extra_args,
4168 code.error_goto_if_null(self.result(), self.pos)))
4169 code.put_gotref(self.py_result())
4170 else:
4171 if self.is_temp:
4172 self.generate_c_operation_code(code)
4174 def type_error(self):
4175 if not (self.operand1.type.is_error
4176 or self.operand2.type.is_error):
4177 error(self.pos, "Invalid operand types for '%s' (%s; %s)" %
4178 (self.operator, self.operand1.type,
4179 self.operand2.type))
4180 self.type = PyrexTypes.error_type
4183 class NumBinopNode(BinopNode):
4184 # Binary operation taking numeric arguments.
4186 def analyse_c_operation(self, env):
4187 type1 = self.operand1.type
4188 type2 = self.operand2.type
4189 self.type = self.compute_c_result_type(type1, type2)
4190 if not self.type:
4191 self.type_error()
4193 def compute_c_result_type(self, type1, type2):
4194 if self.c_types_okay(type1, type2):
4195 return PyrexTypes.widest_numeric_type(type1, type2)
4196 else:
4197 return None
4199 def c_types_okay(self, type1, type2):
4200 #print "NumBinopNode.c_types_okay:", type1, type2 ###
4201 return (type1.is_numeric or type1.is_enum) \
4202 and (type2.is_numeric or type2.is_enum)
4204 def calculate_result_code(self):
4205 return "(%s %s %s)" % (
4206 self.operand1.result(),
4207 self.operator,
4208 self.operand2.result())
4210 def py_operation_function(self):
4211 return self.py_functions[self.operator]
4213 py_functions = {
4214 "|": "PyNumber_Or",
4215 "^": "PyNumber_Xor",
4216 "&": "PyNumber_And",
4217 "<<": "PyNumber_Lshift",
4218 ">>": "PyNumber_Rshift",
4219 "+": "PyNumber_Add",
4220 "-": "PyNumber_Subtract",
4221 "*": "PyNumber_Multiply",
4222 "/": "__Pyx_PyNumber_Divide",
4223 "//": "PyNumber_FloorDivide",
4224 "%": "PyNumber_Remainder",
4225 "**": "PyNumber_Power"
4229 class IntBinopNode(NumBinopNode):
4230 # Binary operation taking integer arguments.
4232 def c_types_okay(self, type1, type2):
4233 #print "IntBinopNode.c_types_okay:", type1, type2 ###
4234 return (type1.is_int or type1.is_enum) \
4235 and (type2.is_int or type2.is_enum)
4238 class AddNode(NumBinopNode):
4239 # '+' operator.
4241 def is_py_operation(self):
4242 if self.operand1.type.is_string \
4243 and self.operand2.type.is_string:
4244 return 1
4245 else:
4246 return NumBinopNode.is_py_operation(self)
4248 def compute_c_result_type(self, type1, type2):
4249 #print "AddNode.compute_c_result_type:", type1, self.operator, type2 ###
4250 if (type1.is_ptr or type1.is_array) and (type2.is_int or type2.is_enum):
4251 return type1
4252 elif (type2.is_ptr or type2.is_array) and (type1.is_int or type1.is_enum):
4253 return type2
4254 else:
4255 return NumBinopNode.compute_c_result_type(
4256 self, type1, type2)
4259 class SubNode(NumBinopNode):
4260 # '-' operator.
4262 def compute_c_result_type(self, type1, type2):
4263 if (type1.is_ptr or type1.is_array) and (type2.is_int or type2.is_enum):
4264 return type1
4265 elif (type1.is_ptr or type1.is_array) and (type2.is_ptr or type2.is_array):
4266 return PyrexTypes.c_int_type
4267 else:
4268 return NumBinopNode.compute_c_result_type(
4269 self, type1, type2)
4272 class MulNode(NumBinopNode):
4273 # '*' operator.
4275 def is_py_operation(self):
4276 type1 = self.operand1.type
4277 type2 = self.operand2.type
4278 if (type1.is_string and type2.is_int) \
4279 or (type2.is_string and type1.is_int):
4280 return 1
4281 else:
4282 return NumBinopNode.is_py_operation(self)
4285 class DivNode(NumBinopNode):
4286 # '/' or '//' operator.
4288 cdivision = None
4290 def generate_evaluation_code(self, code):
4291 if not self.type.is_pyobject:
4292 if self.cdivision is None:
4293 self.cdivision = (code.globalstate.directives['cdivision']
4294 or not self.type.signed
4295 or self.type.is_float)
4296 if not self.cdivision:
4297 code.globalstate.use_utility_code(div_utility_code.specialize(self.type))
4298 NumBinopNode.generate_evaluation_code(self, code)
4300 def calculate_result_code(self):
4301 if self.cdivision:
4302 return "(%s / %s)" % (
4303 self.operand1.result(),
4304 self.operand2.result())
4305 else:
4306 return "__Pyx_div_%s(%s, %s)" % (
4307 self.type.specalization_name(),
4308 self.operand1.result(),
4309 self.operand2.result())
4312 class ModNode(NumBinopNode):
4313 # '%' operator.
4315 cdivision = None
4317 def is_py_operation(self):
4318 return (self.operand1.type.is_string
4319 or self.operand2.type.is_string
4320 or NumBinopNode.is_py_operation(self))
4322 def generate_evaluation_code(self, code):
4323 if not self.type.is_pyobject:
4324 if self.cdivision is None:
4325 self.cdivision = code.globalstate.directives['cdivision'] or not self.type.signed
4326 if not self.cdivision:
4327 math_h_modifier = getattr(self.type, 'math_h_modifier', '__Pyx_INT')
4328 if self.type.is_int:
4329 code.globalstate.use_utility_code(mod_int_helper_macro)
4330 code.globalstate.use_utility_code(mod_utility_code.specialize(self.type, math_h_modifier=math_h_modifier))
4331 NumBinopNode.generate_evaluation_code(self, code)
4333 def calculate_result_code(self):
4334 if self.cdivision:
4335 if self.type.is_float:
4336 return "fmod%s(%s, %s)" % (
4337 self.type.math_h_modifier,
4338 self.operand1.result(),
4339 self.operand2.result())
4340 else:
4341 return "(%s %% %s)" % (
4342 self.operand1.result(),
4343 self.operand2.result())
4344 else:
4345 return "__Pyx_mod_%s(%s, %s)" % (
4346 self.type.specalization_name(),
4347 self.operand1.result(),
4348 self.operand2.result())
4350 class PowNode(NumBinopNode):
4351 # '**' operator.
4353 def analyse_c_operation(self, env):
4354 NumBinopNode.analyse_c_operation(self, env)
4355 if self.operand1.type.is_float or self.operand2.type.is_float:
4356 self.pow_func = "pow"
4357 else:
4358 self.pow_func = "__Pyx_pow_%s" % self.type.declaration_code('').replace(' ', '_')
4359 env.use_utility_code(
4360 int_pow_utility_code.specialize(func_name=self.pow_func,
4361 type=self.type.declaration_code('')))
4363 def calculate_result_code(self):
4364 return "%s(%s, %s)" % (
4365 self.pow_func,
4366 self.operand1.result(),
4367 self.operand2.result())
4370 # Note: This class is temporary "shut down" into an ineffective mode temp
4371 # allocation mode.
4373 # More sophisticated temp reuse was going on before,
4374 # one could have a look at adding this again after /all/ classes
4375 # are converted to the new temp scheme. (The temp juggling cannot work
4376 # otherwise).
4377 class BoolBinopNode(NewTempExprNode):
4378 # Short-circuiting boolean operation.
4380 # operator string
4381 # operand1 ExprNode
4382 # operand2 ExprNode
4384 subexprs = ['operand1', 'operand2']
4386 def calculate_constant_result(self):
4387 if self.operator == 'and':
4388 self.constant_result = \
4389 self.operand1.constant_result and \
4390 self.operand2.constant_result
4391 else:
4392 self.constant_result = \
4393 self.operand1.constant_result or \
4394 self.operand2.constant_result
4396 def compile_time_value(self, denv):
4397 if self.operator == 'and':
4398 return self.operand1.compile_time_value(denv) \
4399 and self.operand2.compile_time_value(denv)
4400 else:
4401 return self.operand1.compile_time_value(denv) \
4402 or self.operand2.compile_time_value(denv)
4404 def coerce_to_boolean(self, env):
4405 self.operand1 = self.operand1.coerce_to_boolean(env)
4406 self.operand2 = self.operand2.coerce_to_boolean(env)
4407 self.type = PyrexTypes.c_bint_type
4408 return self
4410 def analyse_types(self, env):
4411 self.operand1.analyse_types(env)
4412 self.operand2.analyse_types(env)
4413 if self.operand1.type.is_pyobject or \
4414 self.operand2.type.is_pyobject:
4415 self.operand1 = self.operand1.coerce_to_pyobject(env)
4416 self.operand2 = self.operand2.coerce_to_pyobject(env)
4417 self.type = py_object_type
4418 else:
4419 self.operand1 = self.operand1.coerce_to_boolean(env)
4420 self.operand2 = self.operand2.coerce_to_boolean(env)
4421 self.type = PyrexTypes.c_bint_type
4423 # Below disabled for
4425 # For what we're about to do, it's vital that
4426 # both operands be temp nodes.
4427 # self.operand1 = self.operand1.coerce_to_temp(env) #CTT
4428 # self.operand2 = self.operand2.coerce_to_temp(env)
4429 self.is_temp = 1
4431 gil_message = "Truth-testing Python object"
4433 ## def allocate_temps(self, env, result_code = None):
4434 ## # We don't need both operands at the same time, and
4435 ## # one of the operands will also be our result. So we
4436 ## # use an allocation strategy here which results in
4437 ## # this node and both its operands sharing the same
4438 ## # result variable. This allows us to avoid some
4439 ## # assignments and increfs/decrefs that would otherwise
4440 ## # be necessary.
4441 ## self.allocate_temp(env, result_code)
4442 ## self.operand1.allocate_temps(env, self.result())
4443 ## self.operand2.allocate_temps(env, self.result())
4444 ## # We haven't called release_temp on either operand,
4445 ## # because although they are temp nodes, they don't own
4446 ## # their result variable. And because they are temp
4447 ## # nodes, any temps in their subnodes will have been
4448 ## # released before their allocate_temps returned.
4449 ## # Therefore, they contain no temp vars that need to
4450 ## # be released.
4452 def check_const(self):
4453 self.operand1.check_const()
4454 self.operand2.check_const()
4456 def calculate_result_code(self):
4457 return "(%s %s %s)" % (
4458 self.operand1.result(),
4459 self.py_to_c_op[self.operator],
4460 self.operand2.result())
4462 py_to_c_op = {'and': "&&", 'or': "||"}
4464 def generate_evaluation_code(self, code):
4465 code.mark_pos(self.pos)
4466 self.operand1.generate_evaluation_code(code)
4467 test_result, uses_temp = self.generate_operand1_test(code)
4468 if self.operator == 'and':
4469 sense = ""
4470 else:
4471 sense = "!"
4472 code.putln(
4473 "if (%s%s) {" % (
4474 sense,
4475 test_result))
4476 if uses_temp:
4477 code.funcstate.release_temp(test_result)
4478 self.operand1.generate_disposal_code(code)
4479 self.operand2.generate_evaluation_code(code)
4480 self.allocate_temp_result(code)
4481 self.operand2.make_owned_reference(code)
4482 code.putln("%s = %s;" % (self.result(), self.operand2.result()))
4483 self.operand2.generate_post_assignment_code(code)
4484 self.operand2.free_temps(code)
4485 code.putln("} else {")
4486 self.operand1.make_owned_reference(code)
4487 code.putln("%s = %s;" % (self.result(), self.operand1.result()))
4488 self.operand1.generate_post_assignment_code(code)
4489 self.operand1.free_temps(code)
4490 code.putln("}")
4492 def generate_operand1_test(self, code):
4493 # Generate code to test the truth of the first operand.
4494 if self.type.is_pyobject:
4495 test_result = code.funcstate.allocate_temp(PyrexTypes.c_bint_type,
4496 manage_ref=False)
4497 code.putln(
4498 "%s = __Pyx_PyObject_IsTrue(%s); %s" % (
4499 test_result,
4500 self.operand1.py_result(),
4501 code.error_goto_if_neg(test_result, self.pos)))
4502 else:
4503 test_result = self.operand1.result()
4504 return (test_result, self.type.is_pyobject)
4507 class CondExprNode(ExprNode):
4508 # Short-circuiting conditional expression.
4510 # test ExprNode
4511 # true_val ExprNode
4512 # false_val ExprNode
4514 true_val = None
4515 false_val = None
4517 subexprs = ['test', 'true_val', 'false_val']
4519 def calculate_constant_result(self):
4520 if self.test.constant_result:
4521 self.constant_result = self.true_val.constant_result
4522 else:
4523 self.constant_result = self.false_val.constant_result
4525 def analyse_types(self, env):
4526 self.test.analyse_types(env)
4527 self.test = self.test.coerce_to_boolean(env)
4528 self.true_val.analyse_types(env)
4529 self.false_val.analyse_types(env)
4530 self.type = self.compute_result_type(self.true_val.type, self.false_val.type)
4531 if self.true_val.type.is_pyobject or self.false_val.type.is_pyobject:
4532 self.true_val = self.true_val.coerce_to(self.type, env)
4533 self.false_val = self.false_val.coerce_to(self.type, env)
4534 # must be tmp variables so they can share a result
4535 self.true_val = self.true_val.coerce_to_temp(env)
4536 self.false_val = self.false_val.coerce_to_temp(env)
4537 self.is_temp = 1
4538 if self.type == PyrexTypes.error_type:
4539 self.type_error()
4541 def allocate_temps(self, env, result_code = None):
4542 # We only ever evaluate one side, and this is
4543 # after evaluating the truth value, so we may
4544 # use an allocation strategy here which results in
4545 # this node and both its operands sharing the same
4546 # result variable. This allows us to avoid some
4547 # assignments and increfs/decrefs that would otherwise
4548 # be necessary.
4549 self.allocate_temp(env, result_code)
4550 self.test.allocate_temps(env, result_code)
4551 self.true_val.allocate_temps(env, self.result())
4552 self.false_val.allocate_temps(env, self.result())
4553 # We haven't called release_temp on either value,
4554 # because although they are temp nodes, they don't own
4555 # their result variable. And because they are temp
4556 # nodes, any temps in their subnodes will have been
4557 # released before their allocate_temps returned.
4558 # Therefore, they contain no temp vars that need to
4559 # be released.
4561 def compute_result_type(self, type1, type2):
4562 if type1 == type2:
4563 return type1
4564 elif type1.is_numeric and type2.is_numeric:
4565 return PyrexTypes.widest_numeric_type(type1, type2)
4566 elif type1.is_extension_type and type1.subtype_of_resolved_type(type2):
4567 return type2
4568 elif type2.is_extension_type and type2.subtype_of_resolved_type(type1):
4569 return type1
4570 elif type1.is_pyobject or type2.is_pyobject:
4571 return py_object_type
4572 elif type1.assignable_from(type2):
4573 return type1
4574 elif type2.assignable_from(type1):
4575 return type2
4576 else:
4577 return PyrexTypes.error_type
4579 def type_error(self):
4580 if not (self.true_val.type.is_error or self.false_val.type.is_error):
4581 error(self.pos, "Incompatable types in conditional expression (%s; %s)" %
4582 (self.true_val.type, self.false_val.type))
4583 self.type = PyrexTypes.error_type
4585 def check_const(self):
4586 self.test.check_const()
4587 self.true_val.check_const()
4588 self.false_val.check_const()
4590 def generate_evaluation_code(self, code):
4591 self.test.generate_evaluation_code(code)
4592 code.putln("if (%s) {" % self.test.result() )
4593 self.true_val.generate_evaluation_code(code)
4594 code.putln("} else {")
4595 self.false_val.generate_evaluation_code(code)
4596 code.putln("}")
4597 self.test.generate_disposal_code(code)
4598 self.test.free_temps(code)
4600 richcmp_constants = {
4601 "<" : "Py_LT",
4602 "<=": "Py_LE",
4603 "==": "Py_EQ",
4604 "!=": "Py_NE",
4605 "<>": "Py_NE",
4606 ">" : "Py_GT",
4607 ">=": "Py_GE",
4610 class CmpNode(object):
4611 # Mixin class containing code common to PrimaryCmpNodes
4612 # and CascadedCmpNodes.
4614 def calculate_cascaded_constant_result(self, operand1_result):
4615 func = compile_time_binary_operators[self.operator]
4616 operand2_result = self.operand2.constant_result
4617 result = func(operand1_result, operand2_result)
4618 if result and self.cascade:
4619 result = result and \
4620 self.cascade.cascaded_compile_time_value(operand2_result)
4621 self.constant_result = result
4623 def cascaded_compile_time_value(self, operand1, denv):
4624 func = get_compile_time_binop(self)
4625 operand2 = self.operand2.compile_time_value(denv)
4626 try:
4627 result = func(operand1, operand2)
4628 except Exception, e:
4629 self.compile_time_value_error(e)
4630 result = None
4631 if result:
4632 cascade = self.cascade
4633 if cascade:
4634 # FIXME: I bet this must call cascaded_compile_time_value()
4635 result = result and cascade.compile_time_value(operand2, denv)
4636 return result
4638 def is_python_comparison(self):
4639 return (self.has_python_operands()
4640 or (self.cascade and self.cascade.is_python_comparison())
4641 or self.operator in ('in', 'not_in'))
4643 def is_python_result(self):
4644 return ((self.has_python_operands() and self.operator not in ('is', 'is_not', 'in', 'not_in'))
4645 or (self.cascade and self.cascade.is_python_result()))
4647 def check_types(self, env, operand1, op, operand2):
4648 if not self.types_okay(operand1, op, operand2):
4649 error(self.pos, "Invalid types for '%s' (%s, %s)" %
4650 (self.operator, operand1.type, operand2.type))
4652 def types_okay(self, operand1, op, operand2):
4653 type1 = operand1.type
4654 type2 = operand2.type
4655 if type1.is_error or type2.is_error:
4656 return 1
4657 if type1.is_pyobject: # type2 will be, too
4658 return 1
4659 elif type1.is_ptr or type1.is_array:
4660 return type1.is_null_ptr or type2.is_null_ptr \
4661 or ((type2.is_ptr or type2.is_array)
4662 and type1.base_type.same_as(type2.base_type))
4663 elif ((type1.is_numeric and type2.is_numeric
4664 or type1.is_enum and (type1 is type2 or type2.is_int)
4665 or type1.is_int and type2.is_enum)
4666 and op not in ('is', 'is_not')):
4667 return 1
4668 else:
4669 return type1.is_cfunction and type1.is_cfunction and type1 == type2
4671 def generate_operation_code(self, code, result_code,
4672 operand1, op , operand2):
4673 if self.type is PyrexTypes.py_object_type:
4674 coerce_result = "__Pyx_PyBool_FromLong"
4675 else:
4676 coerce_result = ""
4677 if 'not' in op: negation = "!"
4678 else: negation = ""
4679 if op == 'in' or op == 'not_in':
4680 code.putln(
4681 "%s = %s(%sPySequence_Contains(%s, %s)); %s" % (
4682 result_code,
4683 coerce_result,
4684 negation,
4685 operand2.py_result(),
4686 operand1.py_result(),
4687 code.error_goto_if_neg(result_code, self.pos)))
4688 elif (operand1.type.is_pyobject
4689 and op not in ('is', 'is_not')):
4690 code.putln("%s = PyObject_RichCompare(%s, %s, %s); %s" % (
4691 result_code,
4692 operand1.py_result(),
4693 operand2.py_result(),
4694 richcmp_constants[op],
4695 code.error_goto_if_null(result_code, self.pos)))
4696 code.put_gotref(result_code)
4697 else:
4698 type1 = operand1.type
4699 type2 = operand2.type
4700 if (type1.is_extension_type or type2.is_extension_type) \
4701 and not type1.same_as(type2):
4702 common_type = py_object_type
4703 elif type1.is_numeric:
4704 common_type = PyrexTypes.widest_numeric_type(type1, type2)
4705 else:
4706 common_type = type1
4707 code1 = operand1.result_as(common_type)
4708 code2 = operand2.result_as(common_type)
4709 code.putln("%s = %s(%s %s %s);" % (
4710 result_code,
4711 coerce_result,
4712 code1,
4713 self.c_operator(op),
4714 code2))
4716 def c_operator(self, op):
4717 if op == 'is':
4718 return "=="
4719 elif op == 'is_not':
4720 return "!="
4721 else:
4722 return op
4725 class PrimaryCmpNode(NewTempExprNode, CmpNode):
4726 # Non-cascaded comparison or first comparison of
4727 # a cascaded sequence.
4729 # operator string
4730 # operand1 ExprNode
4731 # operand2 ExprNode
4732 # cascade CascadedCmpNode
4734 # We don't use the subexprs mechanism, because
4735 # things here are too complicated for it to handle.
4736 # Instead, we override all the framework methods
4737 # which use it.
4739 child_attrs = ['operand1', 'operand2', 'cascade']
4741 cascade = None
4743 def calculate_constant_result(self):
4744 self.constant_result = self.calculate_cascaded_constant_result(
4745 self.operand1.constant_result)
4747 def compile_time_value(self, denv):
4748 operand1 = self.operand1.compile_time_value(denv)
4749 return self.cascaded_compile_time_value(operand1, denv)
4751 def analyse_types(self, env):
4752 self.operand1.analyse_types(env)
4753 self.operand2.analyse_types(env)
4754 if self.cascade:
4755 self.cascade.analyse_types(env, self.operand2)
4756 self.is_pycmp = self.is_python_comparison()
4757 if self.is_pycmp:
4758 self.coerce_operands_to_pyobjects(env)
4759 if self.has_int_operands():
4760 self.coerce_chars_to_ints(env)
4761 if self.cascade:
4762 self.operand2 = self.operand2.coerce_to_simple(env)
4763 self.cascade.coerce_cascaded_operands_to_temp(env)
4764 self.check_operand_types(env)
4765 if self.is_python_result():
4766 self.type = PyrexTypes.py_object_type
4767 else:
4768 self.type = PyrexTypes.c_bint_type
4769 cdr = self.cascade
4770 while cdr:
4771 cdr.type = self.type
4772 cdr = cdr.cascade
4773 if self.is_pycmp or self.cascade:
4774 self.is_temp = 1
4776 def check_operand_types(self, env):
4777 self.check_types(env,
4778 self.operand1, self.operator, self.operand2)
4779 if self.cascade:
4780 self.cascade.check_operand_types(env, self.operand2)
4782 def has_python_operands(self):
4783 return (self.operand1.type.is_pyobject
4784 or self.operand2.type.is_pyobject)
4786 def coerce_operands_to_pyobjects(self, env):
4787 self.operand1 = self.operand1.coerce_to_pyobject(env)
4788 self.operand2 = self.operand2.coerce_to_pyobject(env)
4789 if self.cascade:
4790 self.cascade.coerce_operands_to_pyobjects(env)
4792 def has_int_operands(self):
4793 return (self.operand1.type.is_int or self.operand2.type.is_int) \
4794 or (self.cascade and self.cascade.has_int_operands())
4796 def coerce_chars_to_ints(self, env):
4797 # coerce literal single-char strings to c chars
4798 if self.operand1.type.is_string and isinstance(self.operand1, StringNode):
4799 self.operand1 = self.operand1.coerce_to(PyrexTypes.c_uchar_type, env)
4800 if self.operand2.type.is_string and isinstance(self.operand2, StringNode):
4801 self.operand2 = self.operand2.coerce_to(PyrexTypes.c_uchar_type, env)
4802 if self.cascade:
4803 self.cascade.coerce_chars_to_ints(env)
4805 def allocate_subexpr_temps(self, env):
4806 self.operand1.allocate_temps(env)
4807 self.operand2.allocate_temps(env)
4808 if self.cascade:
4809 self.cascade.allocate_subexpr_temps(env)
4811 def release_subexpr_temps(self, env):
4812 self.operand1.release_temp(env)
4813 self.operand2.release_temp(env)
4814 if self.cascade:
4815 self.cascade.release_subexpr_temps(env)
4817 def check_const(self):
4818 self.operand1.check_const()
4819 self.operand2.check_const()
4820 if self.cascade:
4821 self.not_const()
4823 def calculate_result_code(self):
4824 return "(%s %s %s)" % (
4825 self.operand1.result(),
4826 self.c_operator(self.operator),
4827 self.operand2.result())
4829 def generate_evaluation_code(self, code):
4830 self.operand1.generate_evaluation_code(code)
4831 self.operand2.generate_evaluation_code(code)
4832 if self.is_temp:
4833 self.allocate_temp_result(code)
4834 self.generate_operation_code(code, self.result(),
4835 self.operand1, self.operator, self.operand2)
4836 if self.cascade:
4837 self.cascade.generate_evaluation_code(code,
4838 self.result(), self.operand2)
4839 self.operand1.generate_disposal_code(code)
4840 self.operand1.free_temps(code)
4841 self.operand2.generate_disposal_code(code)
4842 self.operand2.free_temps(code)
4844 def generate_subexpr_disposal_code(self, code):
4845 # If this is called, it is a non-cascaded cmp,
4846 # so only need to dispose of the two main operands.
4847 self.operand1.generate_disposal_code(code)
4848 self.operand2.generate_disposal_code(code)
4850 def free_subexpr_temps(self, code):
4851 # If this is called, it is a non-cascaded cmp,
4852 # so only need to dispose of the two main operands.
4853 self.operand1.free_temps(code)
4854 self.operand2.free_temps(code)
4856 def annotate(self, code):
4857 self.operand1.annotate(code)
4858 self.operand2.annotate(code)
4859 if self.cascade:
4860 self.cascade.annotate(code)
4863 class CascadedCmpNode(Node, CmpNode):
4864 # A CascadedCmpNode is not a complete expression node. It
4865 # hangs off the side of another comparison node, shares
4866 # its left operand with that node, and shares its result
4867 # with the PrimaryCmpNode at the head of the chain.
4869 # operator string
4870 # operand2 ExprNode
4871 # cascade CascadedCmpNode
4873 child_attrs = ['operand2', 'cascade']
4875 cascade = None
4876 constant_result = constant_value_not_set # FIXME: where to calculate this?
4878 def analyse_types(self, env, operand1):
4879 self.operand2.analyse_types(env)
4880 if self.cascade:
4881 self.cascade.analyse_types(env, self.operand2)
4883 def check_operand_types(self, env, operand1):
4884 self.check_types(env,
4885 operand1, self.operator, self.operand2)
4886 if self.cascade:
4887 self.cascade.check_operand_types(env, self.operand2)
4889 def has_python_operands(self):
4890 return self.operand2.type.is_pyobject
4892 def coerce_operands_to_pyobjects(self, env):
4893 self.operand2 = self.operand2.coerce_to_pyobject(env)
4894 if self.cascade:
4895 self.cascade.coerce_operands_to_pyobjects(env)
4897 def has_int_operands(self):
4898 return self.operand2.type.is_int
4900 def coerce_chars_to_ints(self, env):
4901 if self.operand2.type.is_string and isinstance(self.operand2, StringNode):
4902 self.operand2 = self.operand2.coerce_to(PyrexTypes.c_uchar_type, env)
4904 def coerce_cascaded_operands_to_temp(self, env):
4905 if self.cascade:
4906 #self.operand2 = self.operand2.coerce_to_temp(env) #CTT
4907 self.operand2 = self.operand2.coerce_to_simple(env)
4908 self.cascade.coerce_cascaded_operands_to_temp(env)
4910 def allocate_subexpr_temps(self, env):
4911 self.operand2.allocate_temps(env)
4912 if self.cascade:
4913 self.cascade.allocate_subexpr_temps(env)
4915 def release_subexpr_temps(self, env):
4916 self.operand2.release_temp(env)
4917 if self.cascade:
4918 self.cascade.release_subexpr_temps(env)
4920 def generate_evaluation_code(self, code, result, operand1):
4921 if self.type.is_pyobject:
4922 code.putln("if (__Pyx_PyObject_IsTrue(%s)) {" % result)
4923 code.put_decref(result, self.type)
4924 else:
4925 code.putln("if (%s) {" % result)
4926 self.operand2.generate_evaluation_code(code)
4927 self.generate_operation_code(code, result,
4928 operand1, self.operator, self.operand2)
4929 if self.cascade:
4930 self.cascade.generate_evaluation_code(
4931 code, result, self.operand2)
4932 # Cascaded cmp result is always temp
4933 self.operand2.generate_disposal_code(code)
4934 self.operand2.free_temps(code)
4935 code.putln("}")
4937 def annotate(self, code):
4938 self.operand2.annotate(code)
4939 if self.cascade:
4940 self.cascade.annotate(code)
4943 binop_node_classes = {
4944 "or": BoolBinopNode,
4945 "and": BoolBinopNode,
4946 "|": IntBinopNode,
4947 "^": IntBinopNode,
4948 "&": IntBinopNode,
4949 "<<": IntBinopNode,
4950 ">>": IntBinopNode,
4951 "+": AddNode,
4952 "-": SubNode,
4953 "*": MulNode,
4954 "/": DivNode,
4955 "//": DivNode,
4956 "%": ModNode,
4957 "**": PowNode
4960 def binop_node(pos, operator, operand1, operand2):
4961 # Construct binop node of appropriate class for
4962 # given operator.
4963 return binop_node_classes[operator](pos,
4964 operator = operator,
4965 operand1 = operand1,
4966 operand2 = operand2)
4968 #-------------------------------------------------------------------
4970 # Coercion nodes
4972 # Coercion nodes are special in that they are created during
4973 # the analyse_types phase of parse tree processing.
4974 # Their __init__ methods consequently incorporate some aspects
4975 # of that phase.
4977 #-------------------------------------------------------------------
4979 class CoercionNode(NewTempExprNode):
4980 # Abstract base class for coercion nodes.
4982 # arg ExprNode node being coerced
4984 subexprs = ['arg']
4986 def __init__(self, arg):
4987 self.pos = arg.pos
4988 self.arg = arg
4989 if debug_coercion:
4990 print("%s Coercing %s" % (self, self.arg))
4992 def calculate_constant_result(self):
4993 # constant folding can break type coercion, so this is disabled
4994 pass
4996 def annotate(self, code):
4997 self.arg.annotate(code)
4998 if self.arg.type != self.type:
4999 file, line, col = self.pos
5000 code.annotate((file, line, col-1), AnnotationItem(style='coerce', tag='coerce', text='[%s] to [%s]' % (self.arg.type, self.type)))
5003 class CastNode(CoercionNode):
5004 # Wrap a node in a C type cast.
5006 def __init__(self, arg, new_type):
5007 CoercionNode.__init__(self, arg)
5008 self.type = new_type
5010 def calculate_result_code(self):
5011 return self.arg.result_as(self.type)
5013 def generate_result_code(self, code):
5014 self.arg.generate_result_code(code)
5017 class PyTypeTestNode(CoercionNode):
5018 # This node is used to check that a generic Python
5019 # object is an instance of a particular extension type.
5020 # This node borrows the result of its argument node.
5022 def __init__(self, arg, dst_type, env):
5023 # The arg is know to be a Python object, and
5024 # the dst_type is known to be an extension type.
5025 assert dst_type.is_extension_type or dst_type.is_builtin_type, "PyTypeTest on non extension type"
5026 CoercionNode.__init__(self, arg)
5027 self.type = dst_type
5028 self.result_ctype = arg.ctype()
5030 gil_check = CoercionNode._gil_check
5031 gil_message = "Python type test"
5033 def analyse_types(self, env):
5034 pass
5036 def result_in_temp(self):
5037 return self.arg.result_in_temp()
5039 def is_ephemeral(self):
5040 return self.arg.is_ephemeral()
5042 def calculate_constant_result(self):
5043 # FIXME
5044 pass
5046 def calculate_result_code(self):
5047 return self.arg.result()
5049 def generate_result_code(self, code):
5050 if self.type.typeobj_is_available():
5051 if not self.type.is_builtin_type:
5052 code.globalstate.use_utility_code(type_test_utility_code)
5053 code.putln(
5054 "if (!(%s)) %s" % (
5055 self.type.type_test_code(self.arg.py_result()),
5056 code.error_goto(self.pos)))
5057 else:
5058 error(self.pos, "Cannot test type of extern C class "
5059 "without type object name specification")
5061 def generate_post_assignment_code(self, code):
5062 self.arg.generate_post_assignment_code(code)
5064 def free_temps(self, code):
5065 self.arg.free_temps(code)
5068 class CoerceToPyTypeNode(CoercionNode):
5069 # This node is used to convert a C data type
5070 # to a Python object.
5072 def __init__(self, arg, env):
5073 CoercionNode.__init__(self, arg)
5074 self.type = py_object_type
5075 self.is_temp = 1
5076 if not arg.type.to_py_function or not arg.type.create_convert_utility_code(env):
5077 error(arg.pos,
5078 "Cannot convert '%s' to Python object" % arg.type)
5080 gil_message = "Converting to Python object"
5082 def coerce_to_boolean(self, env):
5083 return self.arg.coerce_to_boolean(env).coerce_to_temp(env)
5085 def coerce_to_integer(self, env):
5086 # If not already some C integer type, coerce to longint.
5087 if self.arg.type.is_int:
5088 return self.arg
5089 else:
5090 return self.arg.coerce_to(PyrexTypes.c_long_type, env)
5092 def analyse_types(self, env):
5093 # The arg is always already analysed
5094 pass
5096 def generate_result_code(self, code):
5097 function = self.arg.type.to_py_function
5098 code.putln('%s = %s(%s); %s' % (
5099 self.result(),
5100 function,
5101 self.arg.result(),
5102 code.error_goto_if_null(self.result(), self.pos)))
5103 code.put_gotref(self.py_result())
5106 class CoerceFromPyTypeNode(CoercionNode):
5107 # This node is used to convert a Python object
5108 # to a C data type.
5110 def __init__(self, result_type, arg, env):
5111 CoercionNode.__init__(self, arg)
5112 self.type = result_type
5113 self.is_temp = 1
5114 if not result_type.from_py_function:
5115 error(arg.pos,
5116 "Cannot convert Python object to '%s'" % result_type)
5117 if self.type.is_string and self.arg.is_ephemeral():
5118 error(arg.pos,
5119 "Obtaining char * from temporary Python value")
5121 def analyse_types(self, env):
5122 # The arg is always already analysed
5123 pass
5125 def generate_result_code(self, code):
5126 function = self.type.from_py_function
5127 operand = self.arg.py_result()
5128 rhs = "%s(%s)" % (function, operand)
5129 if self.type.is_enum:
5130 rhs = typecast(self.type, c_long_type, rhs)
5131 code.putln('%s = %s; %s' % (
5132 self.result(),
5133 rhs,
5134 code.error_goto_if(self.type.error_condition(self.result()), self.pos)))
5135 if self.type.is_pyobject:
5136 code.put_gotref(self.py_result())
5139 class CoerceToBooleanNode(CoercionNode):
5140 # This node is used when a result needs to be used
5141 # in a boolean context.
5143 def __init__(self, arg, env):
5144 CoercionNode.__init__(self, arg)
5145 self.type = PyrexTypes.c_bint_type
5146 if arg.type.is_pyobject:
5147 self.is_temp = 1
5149 def gil_check(self, env):
5150 if self.arg.type.is_pyobject:
5151 self._gil_check(env)
5153 gil_message = "Truth-testing Python object"
5155 def check_const(self):
5156 if self.is_temp:
5157 self.not_const()
5158 self.arg.check_const()
5160 def calculate_result_code(self):
5161 return "(%s != 0)" % self.arg.result()
5163 def generate_result_code(self, code):
5164 if self.arg.type.is_pyobject:
5165 code.putln(
5166 "%s = __Pyx_PyObject_IsTrue(%s); %s" % (
5167 self.result(),
5168 self.arg.py_result(),
5169 code.error_goto_if_neg(self.result(), self.pos)))
5172 class CoerceToTempNode(CoercionNode):
5173 # This node is used to force the result of another node
5174 # to be stored in a temporary. It is only used if the
5175 # argument node's result is not already in a temporary.
5177 def __init__(self, arg, env):
5178 CoercionNode.__init__(self, arg)
5179 self.type = self.arg.type
5180 self.is_temp = 1
5181 if self.type.is_pyobject:
5182 self.result_ctype = py_object_type
5184 gil_message = "Creating temporary Python reference"
5186 def analyse_types(self, env):
5187 # The arg is always already analysed
5188 pass
5190 def coerce_to_boolean(self, env):
5191 self.arg = self.arg.coerce_to_boolean(env)
5192 self.type = self.arg.type
5193 self.result_ctype = self.type
5194 return self
5196 def generate_result_code(self, code):
5197 #self.arg.generate_evaluation_code(code) # Already done
5198 # by generic generate_subexpr_evaluation_code!
5199 code.putln("%s = %s;" % (
5200 self.result(), self.arg.result_as(self.ctype())))
5201 if self.type.is_pyobject:
5202 code.put_incref(self.result(), self.ctype())
5205 class CloneNode(CoercionNode):
5206 # This node is employed when the result of another node needs
5207 # to be used multiple times. The argument node's result must
5208 # be in a temporary. This node "borrows" the result from the
5209 # argument node, and does not generate any evaluation or
5210 # disposal code for it. The original owner of the argument
5211 # node is responsible for doing those things.
5213 subexprs = [] # Arg is not considered a subexpr
5214 gil_check = None
5216 def __init__(self, arg):
5217 CoercionNode.__init__(self, arg)
5218 if hasattr(arg, 'type'):
5219 self.type = arg.type
5220 self.result_ctype = arg.result_ctype
5221 if hasattr(arg, 'entry'):
5222 self.entry = arg.entry
5224 def result(self):
5225 return self.arg.result()
5227 def analyse_types(self, env):
5228 self.type = self.arg.type
5229 self.result_ctype = self.arg.result_ctype
5230 self.is_temp = 1
5231 if hasattr(self.arg, 'entry'):
5232 self.entry = self.arg.entry
5234 def generate_evaluation_code(self, code):
5235 pass
5237 def generate_result_code(self, code):
5238 pass
5240 def generate_disposal_code(self, code):
5241 pass
5243 def allocate_temps(self, env):
5244 pass
5246 def release_temp(self, env):
5247 pass
5249 def free_temps(self, code):
5250 pass
5253 #------------------------------------------------------------------------------------
5255 # Runtime support code
5257 #------------------------------------------------------------------------------------
5259 get_name_interned_utility_code = UtilityCode(
5260 proto = """
5261 static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/
5262 """,
5263 impl = """
5264 static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) {
5265 PyObject *result;
5266 result = PyObject_GetAttr(dict, name);
5267 if (!result)
5268 PyErr_SetObject(PyExc_NameError, name);
5269 return result;
5271 """)
5273 #------------------------------------------------------------------------------------
5275 import_utility_code = UtilityCode(
5276 proto = """
5277 static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/
5278 """,
5279 impl = """
5280 static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) {
5281 PyObject *__import__ = 0;
5282 PyObject *empty_list = 0;
5283 PyObject *module = 0;
5284 PyObject *global_dict = 0;
5285 PyObject *empty_dict = 0;
5286 PyObject *list;
5287 __import__ = __Pyx_GetAttrString(%(BUILTINS)s, "__import__");
5288 if (!__import__)
5289 goto bad;
5290 if (from_list)
5291 list = from_list;
5292 else {
5293 empty_list = PyList_New(0);
5294 if (!empty_list)
5295 goto bad;
5296 list = empty_list;
5298 global_dict = PyModule_GetDict(%(GLOBALS)s);
5299 if (!global_dict)
5300 goto bad;
5301 empty_dict = PyDict_New();
5302 if (!empty_dict)
5303 goto bad;
5304 module = PyObject_CallFunctionObjArgs(__import__,
5305 name, global_dict, empty_dict, list, NULL);
5306 bad:
5307 Py_XDECREF(empty_list);
5308 Py_XDECREF(__import__);
5309 Py_XDECREF(empty_dict);
5310 return module;
5312 """ % {
5313 "BUILTINS": Naming.builtins_cname,
5314 "GLOBALS": Naming.module_cname,
5315 })
5317 #------------------------------------------------------------------------------------
5319 get_exception_utility_code = UtilityCode(
5320 proto = """
5321 static PyObject *__Pyx_GetExcValue(void); /*proto*/
5322 """,
5323 impl = """
5324 static PyObject *__Pyx_GetExcValue(void) {
5325 PyObject *type = 0, *value = 0, *tb = 0;
5326 PyObject *tmp_type, *tmp_value, *tmp_tb;
5327 PyObject *result = 0;
5328 PyThreadState *tstate = PyThreadState_Get();
5329 PyErr_Fetch(&type, &value, &tb);
5330 PyErr_NormalizeException(&type, &value, &tb);
5331 if (PyErr_Occurred())
5332 goto bad;
5333 if (!value) {
5334 value = Py_None;
5335 Py_INCREF(value);
5337 tmp_type = tstate->exc_type;
5338 tmp_value = tstate->exc_value;
5339 tmp_tb = tstate->exc_traceback;
5340 tstate->exc_type = type;
5341 tstate->exc_value = value;
5342 tstate->exc_traceback = tb;
5343 /* Make sure tstate is in a consistent state when we XDECREF
5344 these objects (XDECREF may run arbitrary code). */
5345 Py_XDECREF(tmp_type);
5346 Py_XDECREF(tmp_value);
5347 Py_XDECREF(tmp_tb);
5348 result = value;
5349 Py_XINCREF(result);
5350 type = 0;
5351 value = 0;
5352 tb = 0;
5353 bad:
5354 Py_XDECREF(type);
5355 Py_XDECREF(value);
5356 Py_XDECREF(tb);
5357 return result;
5359 """)
5361 #------------------------------------------------------------------------------------
5363 type_test_utility_code = UtilityCode(
5364 proto = """
5365 static int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); /*proto*/
5366 """,
5367 impl = """
5368 static int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
5369 if (!type) {
5370 PyErr_Format(PyExc_SystemError, "Missing type object");
5371 return 0;
5373 if (obj == Py_None || PyObject_TypeCheck(obj, type))
5374 return 1;
5375 PyErr_Format(PyExc_TypeError, "Cannot convert %s to %s",
5376 Py_TYPE(obj)->tp_name, type->tp_name);
5377 return 0;
5379 """)
5381 #------------------------------------------------------------------------------------
5383 create_class_utility_code = UtilityCode(
5384 proto = """
5385 static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, const char *modname); /*proto*/
5386 """,
5387 impl = """
5388 static PyObject *__Pyx_CreateClass(
5389 PyObject *bases, PyObject *dict, PyObject *name, const char *modname)
5391 PyObject *py_modname;
5392 PyObject *result = 0;
5394 #if PY_MAJOR_VERSION < 3
5395 py_modname = PyString_FromString(modname);
5396 #else
5397 py_modname = PyUnicode_FromString(modname);
5398 #endif
5399 if (!py_modname)
5400 goto bad;
5401 if (PyDict_SetItemString(dict, "__module__", py_modname) < 0)
5402 goto bad;
5403 #if PY_MAJOR_VERSION < 3
5404 result = PyClass_New(bases, dict, name);
5405 #else
5406 result = PyObject_CallFunctionObjArgs((PyObject *)&PyType_Type, name, bases, dict, NULL);
5407 #endif
5408 bad:
5409 Py_XDECREF(py_modname);
5410 return result;
5412 """)
5414 #------------------------------------------------------------------------------------
5416 cpp_exception_utility_code = UtilityCode(
5417 proto = """
5418 #ifndef __Pyx_CppExn2PyErr
5419 static void __Pyx_CppExn2PyErr() {
5420 try {
5421 if (PyErr_Occurred())
5422 ; // let the latest Python exn pass through and ignore the current one
5423 else
5424 throw;
5425 } catch (const std::out_of_range& exn) {
5426 // catch out_of_range explicitly so the proper Python exn may be raised
5427 PyErr_SetString(PyExc_IndexError, exn.what());
5428 } catch (const std::exception& exn) {
5429 PyErr_SetString(PyExc_RuntimeError, exn.what());
5431 catch (...)
5433 PyErr_SetString(PyExc_RuntimeError, "Unknown exception");
5436 #endif
5437 """,
5438 impl = ""
5441 #------------------------------------------------------------------------------------
5443 # If the is_unsigned flag is set, we need to do some extra work to make
5444 # sure the index doesn't become negative.
5446 getitem_int_utility_code = UtilityCode(
5447 proto = """
5449 static INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
5450 PyObject *r;
5451 if (!j) return NULL;
5452 r = PyObject_GetItem(o, j);
5453 Py_DECREF(j);
5454 return r;
5457 """ + ''.join([
5458 """
5459 #define __Pyx_GetItemInt_%(type)s(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \\
5460 __Pyx_GetItemInt_%(type)s_Fast(o, i, size <= sizeof(long)) : \\
5461 __Pyx_GetItemInt_Generic(o, to_py_func(i)))
5463 static INLINE PyObject *__Pyx_GetItemInt_%(type)s_Fast(PyObject *o, Py_ssize_t i, int fits_long) {
5464 if (likely(o != Py_None)) {
5465 if (likely((0 <= i) & (i < Py%(type)s_GET_SIZE(o)))) {
5466 PyObject *r = Py%(type)s_GET_ITEM(o, i);
5467 Py_INCREF(r);
5468 return r;
5470 else if ((-Py%(type)s_GET_SIZE(o) <= i) & (i < 0)) {
5471 PyObject *r = Py%(type)s_GET_ITEM(o, Py%(type)s_GET_SIZE(o) + i);
5472 Py_INCREF(r);
5473 return r;
5476 return __Pyx_GetItemInt_Generic(o, fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i));
5478 """ % {'type' : type_name} for type_name in ('List', 'Tuple')
5479 ]) + """
5481 #define __Pyx_GetItemInt(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \\
5482 __Pyx_GetItemInt_Fast(o, i, size <= sizeof(long)) : \\
5483 __Pyx_GetItemInt_Generic(o, to_py_func(i)))
5485 static INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int fits_long) {
5486 PyObject *r;
5487 if (PyList_CheckExact(o) && ((0 <= i) & (i < PyList_GET_SIZE(o)))) {
5488 r = PyList_GET_ITEM(o, i);
5489 Py_INCREF(r);
5491 else if (PyTuple_CheckExact(o) && ((0 <= i) & (i < PyTuple_GET_SIZE(o)))) {
5492 r = PyTuple_GET_ITEM(o, i);
5493 Py_INCREF(r);
5495 else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_item && (likely(i >= 0))) {
5496 r = PySequence_GetItem(o, i);
5498 else {
5499 r = __Pyx_GetItemInt_Generic(o, fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i));
5501 return r;
5503 """,
5504 impl = """
5505 """)
5509 #------------------------------------------------------------------------------------
5511 setitem_int_utility_code = UtilityCode(
5512 proto = """
5513 #define __Pyx_SetItemInt(o, i, v, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \\
5514 __Pyx_SetItemInt_Fast(o, i, v, size <= sizeof(long)) : \\
5515 __Pyx_SetItemInt_Generic(o, to_py_func(i), v))
5517 static INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) {
5518 int r;
5519 if (!j) return -1;
5520 r = PyObject_SetItem(o, j, v);
5521 Py_DECREF(j);
5522 return r;
5525 static INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v, int fits_long) {
5526 if (PyList_CheckExact(o) && ((0 <= i) & (i < PyList_GET_SIZE(o)))) {
5527 Py_DECREF(PyList_GET_ITEM(o, i));
5528 Py_INCREF(v);
5529 PyList_SET_ITEM(o, i, v);
5530 return 1;
5532 else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_ass_item && (likely(i >= 0)))
5533 return PySequence_SetItem(o, i, v);
5534 else {
5535 PyObject *j = fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i);
5536 return __Pyx_SetItemInt_Generic(o, j, v);
5539 """,
5540 impl = """
5541 """)
5543 #------------------------------------------------------------------------------------
5545 delitem_int_utility_code = UtilityCode(
5546 proto = """
5547 #define __Pyx_DelItemInt(o, i, size, to_py_func) ((size <= sizeof(Py_ssize_t)) ? \\
5548 __Pyx_DelItemInt_Fast(o, i, size <= sizeof(long)) : \\
5549 __Pyx_DelItem_Generic(o, to_py_func(i)))
5551 static INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) {
5552 int r;
5553 if (!j) return -1;
5554 r = PyObject_DelItem(o, j);
5555 Py_DECREF(j);
5556 return r;
5559 static INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i, int fits_long) {
5560 if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_ass_item && likely(i >= 0))
5561 return PySequence_DelItem(o, i);
5562 else {
5563 PyObject *j = fits_long ? PyInt_FromLong(i) : PyLong_FromLongLong(i);
5564 return __Pyx_DelItem_Generic(o, j);
5567 """,
5568 impl = """
5569 """)
5571 #------------------------------------------------------------------------------------
5573 raise_noneattr_error_utility_code = UtilityCode(
5574 proto = """
5575 static INLINE void __Pyx_RaiseNoneAttributeError(const char* attrname);
5576 """,
5577 impl = '''
5578 static INLINE void __Pyx_RaiseNoneAttributeError(const char* attrname) {
5579 PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", attrname);
5581 ''')
5583 raise_noneindex_error_utility_code = UtilityCode(
5584 proto = """
5585 static INLINE void __Pyx_RaiseNoneIndexingError(void);
5586 """,
5587 impl = '''
5588 static INLINE void __Pyx_RaiseNoneIndexingError(void) {
5589 PyErr_SetString(PyExc_TypeError, "'NoneType' object is unsubscriptable");
5591 ''')
5593 raise_none_iter_error_utility_code = UtilityCode(
5594 proto = """
5595 static INLINE void __Pyx_RaiseNoneNotIterableError(void);
5596 """,
5597 impl = '''
5598 static INLINE void __Pyx_RaiseNoneNotIterableError(void) {
5599 PyErr_SetString(PyExc_TypeError, "'NoneType' object is iterable");
5601 ''')
5603 raise_too_many_values_to_unpack = UtilityCode(
5604 proto = """
5605 static INLINE void __Pyx_RaiseTooManyValuesError(void);
5606 """,
5607 impl = '''
5608 static INLINE void __Pyx_RaiseTooManyValuesError(void) {
5609 PyErr_SetString(PyExc_ValueError, "too many values to unpack");
5611 ''')
5613 raise_need_more_values_to_unpack = UtilityCode(
5614 proto = """
5615 static INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index);
5616 """,
5617 impl = '''
5618 static INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) {
5619 PyErr_Format(PyExc_ValueError,
5620 #if PY_VERSION_HEX < 0x02050000
5621 "need more than %d value%s to unpack", (int)index,
5622 #else
5623 "need more than %zd value%s to unpack", index,
5624 #endif
5625 (index == 1) ? "" : "s");
5627 ''')
5629 #------------------------------------------------------------------------------------
5631 tuple_unpacking_error_code = UtilityCode(
5632 proto = """
5633 static void __Pyx_UnpackTupleError(PyObject *, Py_ssize_t index); /*proto*/
5634 """,
5635 impl = """
5636 static void __Pyx_UnpackTupleError(PyObject *t, Py_ssize_t index) {
5637 if (t == Py_None) {
5638 __Pyx_RaiseNoneNotIterableError();
5639 } else if (PyTuple_GET_SIZE(t) < index) {
5640 __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(t));
5641 } else {
5642 __Pyx_RaiseTooManyValuesError();
5645 """,
5646 requires = [raise_none_iter_error_utility_code,
5647 raise_need_more_values_to_unpack,
5648 raise_too_many_values_to_unpack]
5651 unpacking_utility_code = UtilityCode(
5652 proto = """
5653 static PyObject *__Pyx_UnpackItem(PyObject *, Py_ssize_t index); /*proto*/
5654 static int __Pyx_EndUnpack(PyObject *); /*proto*/
5655 """,
5656 impl = """
5657 static PyObject *__Pyx_UnpackItem(PyObject *iter, Py_ssize_t index) {
5658 PyObject *item;
5659 if (!(item = PyIter_Next(iter))) {
5660 if (!PyErr_Occurred()) {
5661 __Pyx_RaiseNeedMoreValuesError(index);
5664 return item;
5667 static int __Pyx_EndUnpack(PyObject *iter) {
5668 PyObject *item;
5669 if ((item = PyIter_Next(iter))) {
5670 Py_DECREF(item);
5671 __Pyx_RaiseTooManyValuesError();
5672 return -1;
5674 else if (!PyErr_Occurred())
5675 return 0;
5676 else
5677 return -1;
5679 """,
5680 requires = [raise_need_more_values_to_unpack,
5681 raise_too_many_values_to_unpack]
5685 #------------------------------------------------------------------------------------
5687 int_pow_utility_code = UtilityCode(
5688 proto="""
5689 static INLINE %(type)s %(func_name)s(%(type)s, %(type)s); /* proto */
5690 """,
5691 impl="""
5692 static INLINE %(type)s %(func_name)s(%(type)s b, %(type)s e) {
5693 %(type)s t = b;
5694 switch (e) {
5695 case 3:
5696 t *= b;
5697 case 2:
5698 t *= b;
5699 case 1:
5700 return t;
5701 case 0:
5702 return 1;
5704 if (unlikely(e<0)) return 0;
5705 t = 1;
5706 while (likely(e)) {
5707 t *= (b * (e&1)) | ((~e)&1); /* 1 or b */
5708 b *= b;
5709 e >>= 1;
5711 return t;
5713 """)
5715 # ------------------------------ Division ------------------------------------
5717 # This is so we can treat floating point and integer mod simultaneously.
5718 mod_int_helper_macro = UtilityCode(proto="""
5719 #define fmod__Pyx_INT(a, b) ((a) % (b))
5720 """)
5722 mod_utility_code = UtilityCode(
5723 proto="""
5724 static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s, %(type)s); /* proto */
5725 """,
5726 impl="""
5727 static INLINE %(type)s __Pyx_mod_%(type_name)s(%(type)s a, %(type)s b) {
5728 %(type)s res = fmod%(math_h_modifier)s(a, b);
5729 res += (res * b < 0) * b;
5730 return res;
5732 """)
5734 div_utility_code = UtilityCode(
5735 proto="""
5736 static INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s, %(type)s); /* proto */
5737 """,
5738 impl="""
5739 static INLINE %(type)s __Pyx_div_%(type_name)s(%(type)s a, %(type)s b) {
5740 %(type)s res = a / b;
5741 res -= (res < 0);
5742 return res;
5744 """)