Cython has moved to github.

cython-devel

view Cython/Compiler/ExprNodes.py @ 1229:c2374c45d350

Optimize conditions when one side of binop is pure C.
author Robert Bradshaw <robertwb@math.washington.edu>
date Thu Oct 09 12:54:36 2008 -0700 (3 years ago)
parents 3c17d33ba344
children fb053eeba704
line source
1 #
2 # Pyrex - Parse tree nodes for expressions
3 #
5 import operator
6 from string import join
8 from Errors import error, warning, InternalError
9 from Errors import hold_errors, release_errors, held_errors, report_error
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, dict_type, unicode_type
16 import Symtab
17 import Options
18 from Annotate import AnnotationItem
20 from Cython.Debugging import print_call_chain
21 from DebugFlags import debug_disposal_code, debug_temp_alloc, \
22 debug_coercion
25 class ExprNode(Node):
26 # subexprs [string] Class var holding names of subexpr node attrs
27 # type PyrexType Type of the result
28 # result_code string Code fragment
29 # result_ctype string C type of result_code if different from type
30 # is_temp boolean Result is in a temporary variable
31 # is_sequence_constructor
32 # boolean Is a list or tuple constructor expression
33 # saved_subexpr_nodes
34 # [ExprNode or [ExprNode or None] or None]
35 # Cached result of subexpr_nodes()
37 result_ctype = None
38 type = None
40 # The Analyse Expressions phase for expressions is split
41 # into two sub-phases:
42 #
43 # Analyse Types
44 # Determines the result type of the expression based
45 # on the types of its sub-expressions, and inserts
46 # coercion nodes into the expression tree where needed.
47 # Marks nodes which will need to have temporary variables
48 # allocated.
49 #
50 # Allocate Temps
51 # Allocates temporary variables where needed, and fills
52 # in the result_code field of each node.
53 #
54 # ExprNode provides some convenience routines which
55 # perform both of the above phases. These should only
56 # be called from statement nodes, and only when no
57 # coercion nodes need to be added around the expression
58 # being analysed. In that case, the above two phases
59 # should be invoked separately.
60 #
61 # Framework code in ExprNode provides much of the common
62 # processing for the various phases. It makes use of the
63 # 'subexprs' class attribute of ExprNodes, which should
64 # contain a list of the names of attributes which can
65 # hold sub-nodes or sequences of sub-nodes.
66 #
67 # The framework makes use of a number of abstract methods.
68 # Their responsibilities are as follows.
69 #
70 # Declaration Analysis phase
71 #
72 # analyse_target_declaration
73 # Called during the Analyse Declarations phase to analyse
74 # the LHS of an assignment or argument of a del statement.
75 # Nodes which cannot be the LHS of an assignment need not
76 # implement it.
77 #
78 # Expression Analysis phase
79 #
80 # analyse_types
81 # - Call analyse_types on all sub-expressions.
82 # - Check operand types, and wrap coercion nodes around
83 # sub-expressions where needed.
84 # - Set the type of this node.
85 # - If a temporary variable will be required for the
86 # result, set the is_temp flag of this node.
87 #
88 # analyse_target_types
89 # Called during the Analyse Types phase to analyse
90 # the LHS of an assignment or argument of a del
91 # statement. Similar responsibilities to analyse_types.
92 #
93 # allocate_temps
94 # - Call allocate_temps for all sub-nodes.
95 # - Call allocate_temp for this node.
96 # - If a temporary was allocated, call release_temp on
97 # all sub-expressions.
98 #
99 # allocate_target_temps
100 # - Call allocate_temps on sub-nodes and allocate any other
101 # temps used during assignment.
102 # - Fill in result_code with a C lvalue if needed.
103 # - If a rhs node is supplied, call release_temp on it.
104 # - Call release_temp on sub-nodes and release any other
105 # temps used during assignment.
106 #
107 # target_code
108 # Called by the default implementation of allocate_target_temps.
109 # Should return a C lvalue for assigning to the node. The default
110 # implementation calls calculate_result_code.
111 #
112 # check_const
113 # - Check that this node and its subnodes form a
114 # legal constant expression. If so, do nothing,
115 # otherwise call not_const.
116 #
117 # The default implementation of check_const
118 # assumes that the expression is not constant.
119 #
120 # check_const_addr
121 # - Same as check_const, except check that the
122 # expression is a C lvalue whose address is
123 # constant. Otherwise, call addr_not_const.
124 #
125 # The default implementation of calc_const_addr
126 # assumes that the expression is not a constant
127 # lvalue.
128 #
129 # Code Generation phase
130 #
131 # generate_evaluation_code
132 # - Call generate_evaluation_code for sub-expressions.
133 # - Perform the functions of generate_result_code
134 # (see below).
135 # - If result is temporary, call generate_disposal_code
136 # on all sub-expressions.
137 #
138 # A default implementation of generate_evaluation_code
139 # is provided which uses the following abstract methods:
140 #
141 # generate_result_code
142 # - Generate any C statements necessary to calculate
143 # the result of this node from the results of its
144 # sub-expressions.
145 #
146 # calculate_result_code
147 # - Should return a C code fragment evaluating to the
148 # result. This is only called when the result is not
149 # a temporary.
150 #
151 # generate_assignment_code
152 # Called on the LHS of an assignment.
153 # - Call generate_evaluation_code for sub-expressions.
154 # - Generate code to perform the assignment.
155 # - If the assignment absorbed a reference, call
156 # generate_post_assignment_code on the RHS,
157 # otherwise call generate_disposal_code on it.
158 #
159 # generate_deletion_code
160 # Called on an argument of a del statement.
161 # - Call generate_evaluation_code for sub-expressions.
162 # - Generate code to perform the deletion.
163 # - Call generate_disposal_code on all sub-expressions.
164 #
165 #
167 is_sequence_constructor = 0
168 is_attribute = 0
170 saved_subexpr_nodes = None
171 is_temp = 0
172 is_target = 0
174 def get_child_attrs(self):
175 return self.subexprs
176 child_attrs = property(fget=get_child_attrs)
178 def not_implemented(self, method_name):
179 print_call_chain(method_name, "not implemented") ###
180 raise InternalError(
181 "%s.%s not implemented" %
182 (self.__class__.__name__, method_name))
184 def is_lvalue(self):
185 return 0
187 def is_ephemeral(self):
188 # An ephemeral node is one whose result is in
189 # a Python temporary and we suspect there are no
190 # other references to it. Certain operations are
191 # disallowed on such values, since they are
192 # likely to result in a dangling pointer.
193 return self.type.is_pyobject and self.is_temp
195 def subexpr_nodes(self):
196 # Extract a list of subexpression nodes based
197 # on the contents of the subexprs class attribute.
198 if self.saved_subexpr_nodes is None:
199 nodes = []
200 for name in self.subexprs:
201 item = getattr(self, name)
202 if item:
203 if isinstance(item, ExprNode):
204 nodes.append(item)
205 else:
206 nodes.extend(item)
207 self.saved_subexpr_nodes = nodes
208 return self.saved_subexpr_nodes
210 def result(self):
211 if not self.is_temp or self.is_target:
212 return self.calculate_result_code()
213 else: # i.e. self.is_temp:
214 return self.result_code
216 def result_as(self, type = None):
217 # Return the result code cast to the specified C type.
218 return typecast(type, self.ctype(), self.result())
220 def py_result(self):
221 # Return the result code cast to PyObject *.
222 return self.result_as(py_object_type)
224 def ctype(self):
225 # Return the native C type of the result (i.e. the
226 # C type of the result_code expression).
227 return self.result_ctype or self.type
229 def compile_time_value(self, denv):
230 # Return value of compile-time expression, or report error.
231 error(self.pos, "Invalid compile-time expression")
233 def compile_time_value_error(self, e):
234 error(self.pos, "Error in compile-time expression: %s: %s" % (
235 e.__class__.__name__, e))
237 # ------------- Declaration Analysis ----------------
239 def analyse_target_declaration(self, env):
240 error(self.pos, "Cannot assign to or delete this")
242 # ------------- Expression Analysis ----------------
244 def analyse_const_expression(self, env):
245 # Called during the analyse_declarations phase of a
246 # constant expression. Analyses the expression's type,
247 # checks whether it is a legal const expression,
248 # and determines its value.
249 self.analyse_types(env)
250 self.allocate_temps(env)
251 self.check_const()
253 def analyse_expressions(self, env):
254 # Convenience routine performing both the Type
255 # Analysis and Temp Allocation phases for a whole
256 # expression.
257 self.analyse_types(env)
258 self.allocate_temps(env)
260 def analyse_target_expression(self, env, rhs):
261 # Convenience routine performing both the Type
262 # Analysis and Temp Allocation phases for the LHS of
263 # an assignment.
264 self.analyse_target_types(env)
265 self.allocate_target_temps(env, rhs)
267 def analyse_boolean_expression(self, env):
268 # Analyse expression and coerce to a boolean.
269 self.analyse_types(env)
270 bool = self.coerce_to_boolean(env)
271 bool.allocate_temps(env)
272 return bool
274 def analyse_temp_boolean_expression(self, env):
275 # Analyse boolean expression and coerce result into
276 # a temporary. This is used when a branch is to be
277 # performed on the result and we won't have an
278 # opportunity to ensure disposal code is executed
279 # afterwards. By forcing the result into a temporary,
280 # we ensure that all disposal has been done by the
281 # time we get the result.
282 self.analyse_types(env)
283 bool = self.coerce_to_boolean(env)
284 temp_bool = bool.coerce_to_temp(env)
285 temp_bool.allocate_temps(env)
286 return temp_bool
288 # --------------- Type Analysis ------------------
290 def analyse_as_module(self, env):
291 # If this node can be interpreted as a reference to a
292 # cimported module, return its scope, else None.
293 return None
295 def analyse_as_type(self, env):
296 # If this node can be interpreted as a reference to a
297 # type, return that type, else None.
298 return None
300 def analyse_as_extension_type(self, env):
301 # If this node can be interpreted as a reference to an
302 # extension type, return its type, else None.
303 return None
305 def analyse_types(self, env):
306 self.not_implemented("analyse_types")
308 def analyse_target_types(self, env):
309 self.analyse_types(env)
311 def gil_assignment_check(self, env):
312 if env.nogil and self.type.is_pyobject:
313 error(self.pos, "Assignment of Python object not allowed without gil")
315 def check_const(self):
316 self.not_const()
318 def not_const(self):
319 error(self.pos, "Not allowed in a constant expression")
321 def check_const_addr(self):
322 self.addr_not_const()
324 def addr_not_const(self):
325 error(self.pos, "Address is not constant")
327 def gil_check(self, env):
328 if env.nogil and self.type.is_pyobject:
329 self.gil_error()
331 # ----------------- Result Allocation -----------------
333 def result_in_temp(self):
334 # Return true if result is in a temporary owned by
335 # this node or one of its subexpressions. Overridden
336 # by certain nodes which can share the result of
337 # a subnode.
338 return self.is_temp
340 def allocate_target_temps(self, env, rhs):
341 # Perform temp allocation for the LHS of an assignment.
342 if debug_temp_alloc:
343 print("%s Allocating target temps" % self)
344 self.allocate_subexpr_temps(env)
345 self.is_target = True
346 if rhs:
347 rhs.release_temp(env)
348 self.release_subexpr_temps(env)
350 def allocate_temps(self, env, result = None):
351 # Allocate temporary variables for this node and
352 # all its sub-expressions. If a result is specified,
353 # this must be a temp node and the specified variable
354 # is used as the result instead of allocating a new
355 # one.
356 if debug_temp_alloc:
357 print("%s Allocating temps" % self)
358 self.allocate_subexpr_temps(env)
359 self.allocate_temp(env, result)
360 if self.is_temp:
361 self.release_subexpr_temps(env)
363 def allocate_subexpr_temps(self, env):
364 # Allocate temporary variables for all sub-expressions
365 # of this node.
366 if debug_temp_alloc:
367 print("%s Allocating temps for: %s" % (self, self.subexprs))
368 for node in self.subexpr_nodes():
369 if node:
370 if debug_temp_alloc:
371 print("%s Allocating temps for %s" % (self, node))
372 node.allocate_temps(env)
374 def allocate_temp(self, env, result = None):
375 # If this node requires a temporary variable for its
376 # result, allocate one, otherwise set the result to
377 # a C code fragment. If a result is specified,
378 # this must be a temp node and the specified variable
379 # is used as the result instead of allocating a new
380 # one.
381 if debug_temp_alloc:
382 print("%s Allocating temp" % self)
383 if result:
384 if not self.is_temp:
385 raise InternalError("Result forced on non-temp node")
386 self.result_code = result
387 elif self.is_temp:
388 type = self.type
389 if not type.is_void:
390 if type.is_pyobject:
391 type = PyrexTypes.py_object_type
392 self.result_code = env.allocate_temp(type)
393 else:
394 self.result_code = None
395 if debug_temp_alloc:
396 print("%s Allocated result %s" % (self, self.result_code))
398 def target_code(self):
399 # Return code fragment for use as LHS of a C assignment.
400 return self.calculate_result_code()
402 def calculate_result_code(self):
403 self.not_implemented("calculate_result_code")
405 # def release_target_temp(self, env):
406 # # Release temporaries used by LHS of an assignment.
407 # self.release_subexpr_temps(env)
409 def release_temp(self, env):
410 # If this node owns a temporary result, release it,
411 # otherwise release results of its sub-expressions.
412 if self.is_temp:
413 if debug_temp_alloc:
414 print("%s Releasing result %s" % (self, self.result_code))
415 env.release_temp(self.result_code)
416 else:
417 self.release_subexpr_temps(env)
419 def release_subexpr_temps(self, env):
420 # Release the results of all sub-expressions of
421 # this node.
422 for node in self.subexpr_nodes():
423 if node:
424 node.release_temp(env)
426 # ---------------- Code Generation -----------------
428 def make_owned_reference(self, code):
429 # If result is a pyobject, make sure we own
430 # a reference to it.
431 if self.type.is_pyobject and not self.result_in_temp():
432 code.put_incref(self.result(), self.ctype())
434 def generate_evaluation_code(self, code):
435 code.mark_pos(self.pos)
436 # Generate code to evaluate this node and
437 # its sub-expressions, and dispose of any
438 # temporary results of its sub-expressions.
439 self.generate_subexpr_evaluation_code(code)
440 self.pre_generate_result_code(code)
441 self.generate_result_code(code)
442 if self.is_temp:
443 self.generate_subexpr_disposal_code(code)
445 def pre_generate_result_code(self, code):
446 pass
448 def generate_subexpr_evaluation_code(self, code):
449 for node in self.subexpr_nodes():
450 node.generate_evaluation_code(code)
452 def generate_result_code(self, code):
453 self.not_implemented("generate_result_code")
455 def generate_disposal_code(self, code):
456 # If necessary, generate code to dispose of
457 # temporary Python reference.
458 if self.is_temp:
459 if self.type.is_pyobject:
460 code.put_decref_clear(self.result(), self.ctype())
461 else:
462 self.generate_subexpr_disposal_code(code)
464 def generate_subexpr_disposal_code(self, code):
465 # Generate code to dispose of temporary results
466 # of all sub-expressions.
467 for node in self.subexpr_nodes():
468 node.generate_disposal_code(code)
470 def generate_post_assignment_code(self, code):
471 # Same as generate_disposal_code except that
472 # assignment will have absorbed a reference to
473 # the result if it is a Python object.
474 if self.is_temp:
475 if self.type.is_pyobject:
476 code.putln("%s = 0;" % self.result())
477 else:
478 self.generate_subexpr_disposal_code(code)
480 def generate_assignment_code(self, rhs, code):
481 # Stub method for nodes which are not legal as
482 # the LHS of an assignment. An error will have
483 # been reported earlier.
484 pass
486 def generate_deletion_code(self, code):
487 # Stub method for nodes that are not legal as
488 # the argument of a del statement. An error
489 # will have been reported earlier.
490 pass
492 # ---------------- Annotation ---------------------
494 def annotate(self, code):
495 for node in self.subexpr_nodes():
496 node.annotate(code)
498 # ----------------- Coercion ----------------------
500 def coerce_to(self, dst_type, env):
501 # Coerce the result so that it can be assigned to
502 # something of type dst_type. If processing is necessary,
503 # wraps this node in a coercion node and returns that.
504 # Otherwise, returns this node unchanged.
505 #
506 # This method is called during the analyse_expressions
507 # phase of the src_node's processing.
508 src = self
509 src_type = self.type
510 src_is_py_type = src_type.is_pyobject
511 dst_is_py_type = dst_type.is_pyobject
513 if dst_type.is_pyobject:
514 if not src.type.is_pyobject:
515 src = CoerceToPyTypeNode(src, env)
516 if not src.type.subtype_of(dst_type):
517 if not isinstance(src, NoneNode):
518 src = PyTypeTestNode(src, dst_type, env)
519 elif src.type.is_pyobject:
520 src = CoerceFromPyTypeNode(dst_type, src, env)
521 else: # neither src nor dst are py types
522 # Added the string comparison, since for c types that
523 # is enough, but Cython gets confused when the types are
524 # in different files.
525 if not (str(src.type) == str(dst_type) or dst_type.assignable_from(src_type)):
526 error(self.pos, "Cannot assign type '%s' to '%s'" %
527 (src.type, dst_type))
528 return src
530 def coerce_to_pyobject(self, env):
531 return self.coerce_to(PyrexTypes.py_object_type, env)
533 def coerce_to_boolean(self, env):
534 # Coerce result to something acceptable as
535 # a boolean value.
536 type = self.type
537 if type.is_pyobject or type.is_ptr or type.is_float:
538 return CoerceToBooleanNode(self, env)
539 else:
540 if not type.is_int and not type.is_error:
541 error(self.pos,
542 "Type '%s' not acceptable as a boolean" % type)
543 return self
545 def coerce_to_integer(self, env):
546 # If not already some C integer type, coerce to longint.
547 if self.type.is_int:
548 return self
549 else:
550 return self.coerce_to(PyrexTypes.c_long_type, env)
552 def coerce_to_temp(self, env):
553 # Ensure that the result is in a temporary.
554 if self.result_in_temp():
555 return self
556 else:
557 return CoerceToTempNode(self, env)
559 def coerce_to_simple(self, env):
560 # Ensure that the result is simple (see is_simple).
561 if self.is_simple():
562 return self
563 else:
564 return self.coerce_to_temp(env)
566 def is_simple(self):
567 # A node is simple if its result is something that can
568 # be referred to without performing any operations, e.g.
569 # a constant, local var, C global var, struct member
570 # reference, or temporary.
571 return self.result_in_temp()
573 def as_cython_attribute(self):
574 return None
577 class NewTempExprNode(ExprNode):
578 backwards_compatible_result = None
580 def result(self):
581 if self.is_temp:
582 return self.temp_code
583 else:
584 return self.calculate_result_code()
586 def allocate_target_temps(self, env, rhs):
587 self.allocate_subexpr_temps(env)
588 rhs.release_temp(rhs)
589 self.release_subexpr_temps(env)
591 def allocate_temps(self, env, result = None):
592 self.allocate_subexpr_temps(env)
593 self.backwards_compatible_result = result
594 if self.is_temp:
595 self.release_subexpr_temps(env)
597 def allocate_temp(self, env, result = None):
598 assert result is None
600 def release_temp(self, env):
601 pass
603 def pre_generate_result_code(self, code):
604 if self.is_temp:
605 type = self.type
606 if not type.is_void:
607 if type.is_pyobject:
608 type = PyrexTypes.py_object_type
609 if self.backwards_compatible_result:
610 self.temp_code = self.backwards_compatible_result
611 else:
612 self.temp_code = code.funcstate.allocate_temp(type)
613 else:
614 self.temp_code = None
616 def generate_disposal_code(self, code):
617 if self.is_temp:
618 if self.type.is_pyobject:
619 code.put_decref_clear(self.result(), self.ctype())
620 if not self.backwards_compatible_result:
621 code.funcstate.release_temp(self.temp_code)
622 else:
623 self.generate_subexpr_disposal_code(code)
625 def generate_post_assignment_code(self, code):
626 if self.is_temp:
627 if self.type.is_pyobject:
628 code.putln("%s = 0;" % self.temp_code)
629 if not self.backwards_compatible_result:
630 code.funcstate.release_temp(self.temp_code)
631 else:
632 self.generate_subexpr_disposal_code(code)
637 class AtomicExprNode(ExprNode):
638 # Abstract base class for expression nodes which have
639 # no sub-expressions.
641 subexprs = []
644 class PyConstNode(AtomicExprNode):
645 # Abstract base class for constant Python values.
647 is_literal = 1
649 def is_simple(self):
650 return 1
652 def analyse_types(self, env):
653 self.type = py_object_type
655 def calculate_result_code(self):
656 return self.value
658 def generate_result_code(self, code):
659 pass
662 class NoneNode(PyConstNode):
663 # The constant value None
665 value = "Py_None"
667 def compile_time_value(self, denv):
668 return None
670 class EllipsisNode(PyConstNode):
671 # '...' in a subscript list.
673 value = "Py_Ellipsis"
675 def compile_time_value(self, denv):
676 return Ellipsis
679 class ConstNode(AtomicExprNode):
680 # Abstract base type for literal constant nodes.
681 #
682 # value string C code fragment
684 is_literal = 1
686 def is_simple(self):
687 return 1
689 def analyse_types(self, env):
690 pass # Types are held in class variables
692 def check_const(self):
693 pass
695 def calculate_result_code(self):
696 return str(self.value)
698 def generate_result_code(self, code):
699 pass
702 class BoolNode(ConstNode):
703 type = PyrexTypes.c_bint_type
704 # The constant value True or False
706 def compile_time_value(self, denv):
707 return self.value
709 def calculate_result_code(self):
710 return str(int(self.value))
712 class NullNode(ConstNode):
713 type = PyrexTypes.c_null_ptr_type
714 value = "NULL"
717 class CharNode(ConstNode):
718 type = PyrexTypes.c_char_type
720 def compile_time_value(self, denv):
721 return ord(self.value)
723 def calculate_result_code(self):
724 return "'%s'" % StringEncoding.escape_character(self.value)
727 class IntNode(ConstNode):
729 # unsigned "" or "U"
730 # longness "" or "L" or "LL"
732 unsigned = ""
733 longness = ""
734 type = PyrexTypes.c_long_type
736 def coerce_to(self, dst_type, env):
737 if dst_type.is_numeric:
738 self.type = PyrexTypes.c_long_type
739 return self
740 # Arrange for a Python version of the number to be pre-allocated
741 # when coercing to a Python type.
742 if dst_type.is_pyobject:
743 self.entry = env.get_py_num(self.value, self.longness)
744 self.type = PyrexTypes.py_object_type
745 # We still need to perform normal coerce_to processing on the
746 # result, because we might be coercing to an extension type,
747 # in which case a type test node will be needed.
748 return ConstNode.coerce_to(self, dst_type, env)
750 def coerce_to_boolean(self, env):
751 self.type = PyrexTypes.c_bint_type
752 return self
754 def calculate_result_code(self):
755 if self.type.is_pyobject:
756 return self.entry.cname
757 else:
758 return str(self.value) + self.unsigned + self.longness
760 def compile_time_value(self, denv):
761 return int(self.value, 0)
764 class FloatNode(ConstNode):
765 type = PyrexTypes.c_double_type
767 def compile_time_value(self, denv):
768 return float(self.value)
770 def calculate_result_code(self):
771 strval = str(self.value)
772 if strval == 'nan':
773 return "(Py_HUGE_VAL * 0)"
774 elif strval == 'inf':
775 return "Py_HUGE_VAL"
776 elif strval == '-inf':
777 return "(-Py_HUGE_VAL)"
778 else:
779 return strval
782 class StringNode(ConstNode):
783 # entry Symtab.Entry
785 type = PyrexTypes.c_char_ptr_type
787 def compile_time_value(self, denv):
788 return self.value
790 def analyse_types(self, env):
791 self.entry = env.add_string_const(self.value)
793 def analyse_as_type(self, env):
794 type = PyrexTypes.parse_basic_type(self.value)
795 if type is not None:
796 return type
797 from TreeFragment import TreeFragment
798 pos = (self.pos[0], self.pos[1], self.pos[2]-7)
799 declaration = TreeFragment(u"sizeof(%s)" % self.value, name=pos[0].filename, initial_pos=pos)
800 sizeof_node = declaration.root.stats[0].expr
801 sizeof_node.analyse_types(env)
802 if isinstance(sizeof_node, SizeofTypeNode):
803 return sizeof_node.arg_type
805 def coerce_to(self, dst_type, env):
806 if dst_type == PyrexTypes.c_char_ptr_type:
807 self.type = PyrexTypes.c_char_ptr_type
808 return self
810 if dst_type.is_int:
811 if not self.type.is_pyobject and len(self.entry.init) == 1:
812 return CharNode(self.pos, value=self.value)
813 else:
814 error(self.pos, "Only coerce single-character ascii strings can be used as ints.")
815 return self
816 # Arrange for a Python version of the string to be pre-allocated
817 # when coercing to a Python type.
818 if dst_type.is_pyobject and not self.type.is_pyobject:
819 node = self.as_py_string_node(env)
820 else:
821 node = self
822 # We still need to perform normal coerce_to processing on the
823 # result, because we might be coercing to an extension type,
824 # in which case a type test node will be needed.
825 return ConstNode.coerce_to(node, dst_type, env)
827 def as_py_string_node(self, env):
828 # Return a new StringNode with the same entry as this node
829 # but whose type is a Python type instead of a C type.
830 entry = self.entry
831 env.add_py_string(entry)
832 return StringNode(self.pos, value = self.value, entry = entry, type = py_object_type)
834 def calculate_result_code(self):
835 if self.type.is_pyobject:
836 return self.entry.pystring_cname
837 else:
838 return self.entry.cname
841 class UnicodeNode(PyConstNode):
842 # entry Symtab.Entry
844 type = unicode_type
846 def analyse_types(self, env):
847 self.entry = env.add_string_const(self.value)
848 env.add_py_string(self.entry)
850 def calculate_result_code(self):
851 return self.entry.pystring_cname
853 def _coerce_to(self, dst_type, env):
854 if not dst_type.is_pyobject:
855 node = StringNode(self.pos, entry = entry, type = py_object_type)
856 return ConstNode.coerce_to(node, dst_type, env)
857 else:
858 return self
859 # We still need to perform normal coerce_to processing on the
860 # result, because we might be coercing to an extension type,
861 # in which case a type test node will be needed.
863 def compile_time_value(self, env):
864 return self.value
867 class IdentifierStringNode(ConstNode):
868 # A Python string that behaves like an identifier, e.g. for
869 # keyword arguments in a call, or for imported names
870 type = PyrexTypes.py_object_type
872 def analyse_types(self, env):
873 self.cname = env.intern_identifier(self.value)
875 def calculate_result_code(self):
876 return self.cname
879 class LongNode(AtomicExprNode):
880 # Python long integer literal
881 #
882 # value string
884 def compile_time_value(self, denv):
885 return long(self.value)
887 gil_message = "Constructing Python long int"
889 def analyse_types(self, env):
890 self.type = py_object_type
891 self.gil_check(env)
892 self.is_temp = 1
894 gil_message = "Constructing Python long int"
896 def generate_evaluation_code(self, code):
897 code.putln(
898 '%s = PyLong_FromString("%s", 0, 0); %s' % (
899 self.result(),
900 self.value,
901 code.error_goto_if_null(self.result(), self.pos)))
904 class ImagNode(AtomicExprNode):
905 # Imaginary number literal
906 #
907 # value float imaginary part
909 def compile_time_value(self, denv):
910 return complex(0.0, self.value)
912 def analyse_types(self, env):
913 self.type = py_object_type
914 self.gil_check(env)
915 self.is_temp = 1
917 gil_message = "Constructing complex number"
919 def generate_evaluation_code(self, code):
920 code.putln(
921 "%s = PyComplex_FromDoubles(0.0, %s); %s" % (
922 self.result(),
923 self.value,
924 code.error_goto_if_null(self.result(), self.pos)))
927 class NameNode(AtomicExprNode):
928 # Reference to a local or global variable name.
929 #
930 # name string Python name of the variable
931 #
932 # entry Entry Symbol table entry
933 # interned_cname string
935 is_name = True
936 is_cython_module = False
937 cython_attribute = None
938 skip_assignment_decref = False
939 entry = None
941 def create_analysed_rvalue(pos, env, entry):
942 node = NameNode(pos)
943 node.analyse_types(env, entry=entry)
944 return node
946 def as_cython_attribute(self):
947 return self.cython_attribute
949 create_analysed_rvalue = staticmethod(create_analysed_rvalue)
951 def compile_time_value(self, denv):
952 try:
953 return denv.lookup(self.name)
954 except KeyError:
955 error(self.pos, "Compile-time name '%s' not defined" % self.name)
957 def coerce_to(self, dst_type, env):
958 # If coercing to a generic pyobject and this is a builtin
959 # C function with a Python equivalent, manufacture a NameNode
960 # referring to the Python builtin.
961 #print "NameNode.coerce_to:", self.name, dst_type ###
962 if dst_type is py_object_type:
963 entry = self.entry
964 if entry and entry.is_cfunction:
965 var_entry = entry.as_variable
966 if var_entry:
967 if var_entry.is_builtin and Options.cache_builtins:
968 var_entry = env.declare_builtin(var_entry.name, self.pos)
969 node = NameNode(self.pos, name = self.name)
970 node.entry = var_entry
971 node.analyse_rvalue_entry(env)
972 return node
973 return AtomicExprNode.coerce_to(self, dst_type, env)
975 def analyse_as_module(self, env):
976 # Try to interpret this as a reference to a cimported module.
977 # Returns the module scope, or None.
978 entry = self.entry
979 if not entry:
980 entry = env.lookup(self.name)
981 if entry and entry.as_module:
982 return entry.as_module
983 return None
985 def analyse_as_type(self, env):
986 if self.cython_attribute:
987 type = PyrexTypes.parse_basic_type(self.cython_attribute)
988 else:
989 type = PyrexTypes.parse_basic_type(self.name)
990 if type:
991 return type
992 entry = self.entry
993 if not entry:
994 entry = env.lookup(self.name)
995 if entry and entry.is_type:
996 return entry.type
997 else:
998 return None
1000 def analyse_as_extension_type(self, env):
1001 # Try to interpret this as a reference to an extension type.
1002 # Returns the extension type, or None.
1003 entry = self.entry
1004 if not entry:
1005 entry = env.lookup(self.name)
1006 if entry and entry.is_type and entry.type.is_extension_type:
1007 return entry.type
1008 else:
1009 return None
1011 def analyse_target_declaration(self, env):
1012 if not self.entry:
1013 self.entry = env.lookup_here(self.name)
1014 if not self.entry:
1015 self.entry = env.declare_var(self.name, py_object_type, self.pos)
1016 env.control_flow.set_state(self.pos, (self.name, 'initalized'), True)
1017 env.control_flow.set_state(self.pos, (self.name, 'source'), 'assignment')
1018 if self.entry.is_declared_generic:
1019 self.result_ctype = py_object_type
1021 def analyse_types(self, env):
1022 if self.entry is None:
1023 self.entry = env.lookup(self.name)
1024 if not self.entry:
1025 self.entry = env.declare_builtin(self.name, self.pos)
1026 if not self.entry:
1027 self.type = PyrexTypes.error_type
1028 return
1029 self.analyse_rvalue_entry(env)
1031 def analyse_target_types(self, env):
1032 self.analyse_entry(env)
1033 if not self.is_lvalue():
1034 error(self.pos, "Assignment to non-lvalue '%s'"
1035 % self.name)
1036 self.type = PyrexTypes.error_type
1037 self.entry.used = 1
1038 if self.entry.type.is_buffer:
1039 import Buffer
1040 Buffer.used_buffer_aux_vars(self.entry)
1042 def analyse_rvalue_entry(self, env):
1043 #print "NameNode.analyse_rvalue_entry:", self.name ###
1044 #print "Entry:", self.entry.__dict__ ###
1045 self.analyse_entry(env)
1046 entry = self.entry
1047 if entry.is_declared_generic:
1048 self.result_ctype = py_object_type
1049 if entry.is_pyglobal or entry.is_builtin:
1050 if Options.cache_builtins and entry.is_builtin:
1051 self.is_temp = 0
1052 else:
1053 self.is_temp = 1
1054 env.use_utility_code(get_name_interned_utility_code)
1055 self.gil_check(env)
1057 gil_message = "Accessing Python global or builtin"
1059 def analyse_entry(self, env):
1060 #print "NameNode.analyse_entry:", self.name ###
1061 self.check_identifier_kind()
1062 entry = self.entry
1063 type = entry.type
1064 self.type = type
1065 if entry.is_pyglobal or entry.is_builtin:
1066 assert type.is_pyobject, "Python global or builtin not a Python object"
1067 self.interned_cname = self.entry.interned_cname = \
1068 env.intern_identifier(self.entry.name)
1070 def check_identifier_kind(self):
1071 #print "NameNode.check_identifier_kind:", self.entry.name ###
1072 #print self.entry.__dict__ ###
1073 entry = self.entry
1074 #entry.used = 1
1075 if not (entry.is_const or entry.is_variable
1076 or entry.is_builtin or entry.is_cfunction):
1077 if self.entry.as_variable:
1078 self.entry = self.entry.as_variable
1079 else:
1080 error(self.pos,
1081 "'%s' is not a constant, variable or function identifier" % self.name)
1083 def is_simple(self):
1084 # If it's not a C variable, it'll be in a temp.
1085 return 1
1087 def calculate_target_results(self, env):
1088 pass
1090 def check_const(self):
1091 entry = self.entry
1092 if entry is not None and not (entry.is_const or entry.is_cfunction or entry.is_builtin):
1093 self.not_const()
1095 def check_const_addr(self):
1096 entry = self.entry
1097 if not (entry.is_cglobal or entry.is_cfunction or entry.is_builtin):
1098 self.addr_not_const()
1100 def is_lvalue(self):
1101 return self.entry.is_variable and \
1102 not self.entry.type.is_array and \
1103 not self.entry.is_readonly
1105 def is_ephemeral(self):
1106 # Name nodes are never ephemeral, even if the
1107 # result is in a temporary.
1108 return 0
1110 def allocate_temp(self, env, result = None):
1111 AtomicExprNode.allocate_temp(self, env, result)
1112 entry = self.entry
1113 if entry:
1114 entry.used = 1
1115 if entry.type.is_buffer:
1116 import Buffer
1117 Buffer.used_buffer_aux_vars(entry)
1118 if entry.utility_code:
1119 env.use_utility_code(entry.utility_code)
1121 def calculate_result_code(self):
1122 entry = self.entry
1123 if not entry:
1124 return "<error>" # There was an error earlier
1125 return entry.cname
1127 def generate_result_code(self, code):
1128 assert hasattr(self, 'entry')
1129 entry = self.entry
1130 if entry is None:
1131 return # There was an error earlier
1132 if entry.is_builtin and Options.cache_builtins:
1133 return # Lookup already cached
1134 elif entry.is_pyglobal or entry.is_builtin:
1135 if entry.is_builtin:
1136 namespace = Naming.builtins_cname
1137 else: # entry.is_pyglobal
1138 namespace = entry.scope.namespace_cname
1139 code.putln(
1140 '%s = __Pyx_GetName(%s, %s); %s' % (
1141 self.result(),
1142 namespace,
1143 self.interned_cname,
1144 code.error_goto_if_null(self.result(), self.pos)))
1145 elif entry.is_local and False:
1146 # control flow not good enough yet
1147 assigned = entry.scope.control_flow.get_state((entry.name, 'initalized'), self.pos)
1148 if assigned is False:
1149 error(self.pos, "local variable '%s' referenced before assignment" % entry.name)
1150 elif not Options.init_local_none and assigned is None:
1151 code.putln('if (%s == 0) { PyErr_SetString(PyExc_UnboundLocalError, "%s"); %s }' % (entry.cname, entry.name, code.error_goto(self.pos)))
1152 entry.scope.control_flow.set_state(self.pos, (entry.name, 'initalized'), True)
1154 def generate_assignment_code(self, rhs, code):
1155 #print "NameNode.generate_assignment_code:", self.name ###
1156 entry = self.entry
1157 if entry is None:
1158 return # There was an error earlier
1160 # is_pyglobal seems to be True for module level-globals only.
1161 # We use this to access class->tp_dict if necessary.
1162 if entry.is_pyglobal:
1163 namespace = self.entry.scope.namespace_cname
1164 if entry.is_member:
1165 # if the entry is a member we have to cheat: SetAttr does not work
1166 # on types, so we create a descriptor which is then added to tp_dict
1167 code.put_error_if_neg(self.pos,
1168 'PyDict_SetItem(%s->tp_dict, %s, %s)' % (
1169 namespace,
1170 self.interned_cname,
1171 rhs.py_result()))
1172 # in Py2.6+, we need to invalidate the method cache
1173 code.putln("PyType_Modified(%s);" %
1174 entry.scope.parent_type.typeptr_cname)
1175 else:
1176 code.put_error_if_neg(self.pos,
1177 'PyObject_SetAttr(%s, %s, %s)' % (
1178 namespace,
1179 self.interned_cname,
1180 rhs.py_result()))
1181 if debug_disposal_code:
1182 print("NameNode.generate_assignment_code:")
1183 print("...generating disposal code for %s" % rhs)
1184 rhs.generate_disposal_code(code)
1186 else:
1187 if self.type.is_buffer:
1188 # Generate code for doing the buffer release/acquisition.
1189 # This might raise an exception in which case the assignment (done
1190 # below) will not happen.
1192 # The reason this is not in a typetest-like node is because the
1193 # variables that the acquired buffer info is stored to is allocated
1194 # per entry and coupled with it.
1195 self.generate_acquire_buffer(rhs, code)
1197 if self.type.is_pyobject:
1198 rhs.make_owned_reference(code)
1199 #print "NameNode.generate_assignment_code: to", self.name ###
1200 #print "...from", rhs ###
1201 #print "...LHS type", self.type, "ctype", self.ctype() ###
1202 #print "...RHS type", rhs.type, "ctype", rhs.ctype() ###
1203 if not self.skip_assignment_decref:
1204 if entry.is_local and not Options.init_local_none:
1205 initalized = entry.scope.control_flow.get_state((entry.name, 'initalized'), self.pos)
1206 if initalized is True:
1207 code.put_decref(self.result(), self.ctype())
1208 elif initalized is None:
1209 code.put_xdecref(self.result(), self.ctype())
1210 else:
1211 code.put_decref(self.result(), self.ctype())
1212 code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
1213 if debug_disposal_code:
1214 print("NameNode.generate_assignment_code:")
1215 print("...generating post-assignment code for %s" % rhs)
1216 rhs.generate_post_assignment_code(code)
1218 def generate_acquire_buffer(self, rhs, code):
1219 rhstmp = code.funcstate.allocate_temp(self.entry.type)
1220 buffer_aux = self.entry.buffer_aux
1221 bufstruct = buffer_aux.buffer_info_var.cname
1222 code.putln('%s = %s;' % (rhstmp, rhs.result_as(self.ctype())))
1224 import Buffer
1225 Buffer.put_assign_to_buffer(self.result(), rhstmp, buffer_aux, self.entry.type,
1226 is_initialized=not self.skip_assignment_decref,
1227 pos=self.pos, code=code)
1228 code.putln("%s = 0;" % rhstmp)
1229 code.funcstate.release_temp(rhstmp)
1231 def generate_deletion_code(self, code):
1232 if self.entry is None:
1233 return # There was an error earlier
1234 if not self.entry.is_pyglobal:
1235 error(self.pos, "Deletion of local or C global name not supported")
1236 return
1237 code.put_error_if_neg(self.pos,
1238 'PyObject_DelAttrString(%s, "%s")' % (
1239 Naming.module_cname,
1240 self.entry.name))
1242 def annotate(self, code):
1243 if hasattr(self, 'is_called') and self.is_called:
1244 pos = (self.pos[0], self.pos[1], self.pos[2] - len(self.name) - 1)
1245 if self.type.is_pyobject:
1246 code.annotate(pos, AnnotationItem('py_call', 'python function', size=len(self.name)))
1247 else:
1248 code.annotate(pos, AnnotationItem('c_call', 'c function', size=len(self.name)))
1250 class BackquoteNode(ExprNode):
1251 # `expr`
1253 # arg ExprNode
1255 subexprs = ['arg']
1257 def analyse_types(self, env):
1258 self.arg.analyse_types(env)
1259 self.arg = self.arg.coerce_to_pyobject(env)
1260 self.type = py_object_type
1261 self.gil_check(env)
1262 self.is_temp = 1
1264 gil_message = "Backquote expression"
1266 def generate_result_code(self, code):
1267 code.putln(
1268 "%s = PyObject_Repr(%s); %s" % (
1269 self.result(),
1270 self.arg.py_result(),
1271 code.error_goto_if_null(self.result(), self.pos)))
1274 class ImportNode(ExprNode):
1275 # Used as part of import statement implementation.
1276 # Implements result =
1277 # __import__(module_name, globals(), None, name_list)
1279 # module_name IdentifierStringNode dotted name of module
1280 # name_list ListNode or None list of names to be imported
1282 subexprs = ['module_name', 'name_list']
1284 def analyse_types(self, env):
1285 self.module_name.analyse_types(env)
1286 self.module_name = self.module_name.coerce_to_pyobject(env)
1287 if self.name_list:
1288 self.name_list.analyse_types(env)
1289 self.name_list.coerce_to_pyobject(env)
1290 self.type = py_object_type
1291 self.gil_check(env)
1292 self.is_temp = 1
1293 env.use_utility_code(import_utility_code)
1295 gil_message = "Python import"
1297 def generate_result_code(self, code):
1298 if self.name_list:
1299 name_list_code = self.name_list.py_result()
1300 else:
1301 name_list_code = "0"
1302 code.putln(
1303 "%s = __Pyx_Import(%s, %s); %s" % (
1304 self.result(),
1305 self.module_name.py_result(),
1306 name_list_code,
1307 code.error_goto_if_null(self.result(), self.pos)))
1310 class IteratorNode(ExprNode):
1311 # Used as part of for statement implementation.
1312 # Implements result = iter(sequence)
1314 # sequence ExprNode
1316 subexprs = ['sequence']
1318 def analyse_types(self, env):
1319 self.sequence.analyse_types(env)
1320 self.sequence = self.sequence.coerce_to_pyobject(env)
1321 self.type = py_object_type
1322 self.gil_check(env)
1323 self.is_temp = 1
1325 self.counter = TempNode(self.pos, PyrexTypes.c_py_ssize_t_type, env)
1326 self.counter.allocate_temp(env)
1328 gil_message = "Iterating over Python object"
1330 def release_temp(self, env):
1331 env.release_temp(self.result())
1332 self.counter.release_temp(env)
1334 def generate_result_code(self, code):
1335 code.putln(
1336 "if (PyList_CheckExact(%s) || PyTuple_CheckExact(%s)) {" % (
1337 self.sequence.py_result(),
1338 self.sequence.py_result()))
1339 code.putln(
1340 "%s = 0; %s = %s; Py_INCREF(%s);" % (
1341 self.counter.result(),
1342 self.result(),
1343 self.sequence.py_result(),
1344 self.result()))
1345 code.putln("} else {")
1346 code.putln("%s = -1; %s = PyObject_GetIter(%s); %s" % (
1347 self.counter.result(),
1348 self.result(),
1349 self.sequence.py_result(),
1350 code.error_goto_if_null(self.result(), self.pos)))
1351 code.putln("}")
1354 class NextNode(AtomicExprNode):
1355 # Used as part of for statement implementation.
1356 # Implements result = iterator.next()
1357 # Created during analyse_types phase.
1358 # The iterator is not owned by this node.
1360 # iterator ExprNode
1362 def __init__(self, iterator, env):
1363 self.pos = iterator.pos
1364 self.iterator = iterator
1365 self.type = py_object_type
1366 self.is_temp = 1
1368 def generate_result_code(self, code):
1369 for py_type in ["List", "Tuple"]:
1370 code.putln(
1371 "if (likely(Py%s_CheckExact(%s))) {" % (py_type, self.iterator.py_result()))
1372 code.putln(
1373 "if (%s >= Py%s_GET_SIZE(%s)) break;" % (
1374 self.iterator.counter.result(),
1375 py_type,
1376 self.iterator.py_result()))
1377 code.putln(
1378 "%s = Py%s_GET_ITEM(%s, %s); Py_INCREF(%s); %s++;" % (
1379 self.result(),
1380 py_type,
1381 self.iterator.py_result(),
1382 self.iterator.counter.result(),
1383 self.result(),
1384 self.iterator.counter.result()))
1385 code.put("} else ")
1386 code.putln("{")
1387 code.putln(
1388 "%s = PyIter_Next(%s);" % (
1389 self.result(),
1390 self.iterator.py_result()))
1391 code.putln(
1392 "if (!%s) {" %
1393 self.result())
1394 code.putln(code.error_goto_if_PyErr(self.pos))
1395 code.putln("break;")
1396 code.putln("}")
1397 code.putln("}")
1400 class ExcValueNode(AtomicExprNode):
1401 # Node created during analyse_types phase
1402 # of an ExceptClauseNode to fetch the current
1403 # exception value.
1405 def __init__(self, pos, env, var):
1406 ExprNode.__init__(self, pos)
1407 self.type = py_object_type
1408 self.var = var
1410 def calculate_result_code(self):
1411 return self.var
1413 def generate_result_code(self, code):
1414 pass
1416 def analyse_types(self, env):
1417 pass
1420 class TempNode(AtomicExprNode):
1421 # Node created during analyse_types phase
1422 # of some nodes to hold a temporary value.
1424 def __init__(self, pos, type, env):
1425 ExprNode.__init__(self, pos)
1426 self.type = type
1427 if type.is_pyobject:
1428 self.result_ctype = py_object_type
1429 self.is_temp = 1
1431 def analyse_types(self, env):
1432 return self.type
1434 def generate_result_code(self, code):
1435 pass
1438 class PyTempNode(TempNode):
1439 # TempNode holding a Python value.
1441 def __init__(self, pos, env):
1442 TempNode.__init__(self, pos, PyrexTypes.py_object_type, env)
1445 #-------------------------------------------------------------------
1447 # Trailer nodes
1449 #-------------------------------------------------------------------
1451 class IndexNode(ExprNode):
1452 # Sequence indexing.
1454 # base ExprNode
1455 # index ExprNode
1456 # indices [ExprNode]
1457 # is_buffer_access boolean Whether this is a buffer access.
1459 # indices is used on buffer access, index on non-buffer access.
1460 # The former contains a clean list of index parameters, the
1461 # latter whatever Python object is needed for index access.
1463 subexprs = ['base', 'index', 'indices']
1464 indices = None
1466 def __init__(self, pos, index, *args, **kw):
1467 ExprNode.__init__(self, pos, index=index, *args, **kw)
1468 self._index = index
1470 def compile_time_value(self, denv):
1471 base = self.base.compile_time_value(denv)
1472 index = self.index.compile_time_value(denv)
1473 try:
1474 return base[index]
1475 except Exception, e:
1476 self.compile_time_value_error(e)
1478 def is_ephemeral(self):
1479 return self.base.is_ephemeral()
1481 def analyse_target_declaration(self, env):
1482 pass
1484 def analyse_as_type(self, env):
1485 base_type = self.base.analyse_as_type(env)
1486 if base_type and not base_type.is_pyobject:
1487 return PyrexTypes.CArrayType(base_type, int(self.index.compile_time_value(env)))
1488 return None
1490 def analyse_types(self, env):
1491 self.analyse_base_and_index_types(env, getting = 1)
1493 def analyse_target_types(self, env):
1494 self.analyse_base_and_index_types(env, setting = 1)
1496 def analyse_base_and_index_types(self, env, getting = 0, setting = 0):
1497 # Note: This might be cleaned up by having IndexNode
1498 # parsed in a saner way and only construct the tuple if
1499 # needed.
1501 # Note that this function must leave IndexNode in a cloneable state.
1502 # For buffers, self.index is packed out on the initial analysis, and
1503 # when cloning self.indices is copied.
1504 self.is_buffer_access = False
1506 self.base.analyse_types(env)
1507 # Handle the case where base is a literal char* (and we expect a string, not an int)
1508 if isinstance(self.base, StringNode):
1509 self.base = self.base.coerce_to_pyobject(env)
1511 skip_child_analysis = False
1512 buffer_access = False
1513 if self.base.type.is_buffer:
1514 assert hasattr(self.base, "entry") # Must be a NameNode-like node
1515 if self.indices:
1516 indices = self.indices
1517 else:
1518 # On cloning, indices is cloned. Otherwise, unpack index into indices
1519 assert not isinstance(self.index, CloneNode)
1520 if isinstance(self.index, TupleNode):
1521 indices = self.index.args
1522 else:
1523 indices = [self.index]
1524 if len(indices) == self.base.type.ndim:
1525 buffer_access = True
1526 skip_child_analysis = True
1527 for x in indices:
1528 x.analyse_types(env)
1529 if not x.type.is_int:
1530 buffer_access = False
1532 if buffer_access:
1533 self.indices = indices
1534 self.index = None
1535 self.type = self.base.type.dtype
1536 self.is_buffer_access = True
1537 self.buffer_type = self.base.entry.type
1539 if getting and self.type.is_pyobject:
1540 self.is_temp = True
1541 if setting:
1542 if not self.base.entry.type.writable:
1543 error(self.pos, "Writing to readonly buffer")
1544 else:
1545 self.base.entry.buffer_aux.writable_needed = True
1546 else:
1547 if isinstance(self.index, TupleNode):
1548 self.index.analyse_types(env, skip_children=skip_child_analysis)
1549 elif not skip_child_analysis:
1550 self.index.analyse_types(env)
1551 if self.base.type.is_pyobject:
1552 if self.index.type.is_int and not self.index.type.is_longlong:
1553 self.original_index_type = self.index.type
1554 self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env).coerce_to_simple(env)
1555 if getting:
1556 env.use_utility_code(getitem_int_utility_code)
1557 if setting:
1558 env.use_utility_code(setitem_int_utility_code)
1559 else:
1560 self.index = self.index.coerce_to_pyobject(env)
1561 self.type = py_object_type
1562 self.gil_check(env)
1563 self.is_temp = 1
1564 else:
1565 if self.base.type.is_ptr or self.base.type.is_array:
1566 self.type = self.base.type.base_type
1567 else:
1568 error(self.pos,
1569 "Attempting to index non-array type '%s'" %
1570 self.base.type)
1571 self.type = PyrexTypes.error_type
1572 if self.index.type.is_pyobject:
1573 self.index = self.index.coerce_to(
1574 PyrexTypes.c_py_ssize_t_type, env)
1575 if not self.index.type.is_int:
1576 error(self.pos,
1577 "Invalid index type '%s'" %
1578 self.index.type)
1580 gil_message = "Indexing Python object"
1582 def check_const_addr(self):
1583 self.base.check_const_addr()
1584 self.index.check_const()
1586 def is_lvalue(self):
1587 return 1
1589 def calculate_result_code(self):
1590 if self.is_buffer_access:
1591 return "(*%s)" % self.buffer_ptr_code
1592 else:
1593 return "(%s[%s])" % (
1594 self.base.result(), self.index.result())
1596 def index_unsigned_parameter(self):
1597 if self.index.type.is_int:
1598 if self.original_index_type.signed:
1599 return ", 0"
1600 else:
1601 return ", sizeof(Py_ssize_t) <= sizeof(%s)" % self.original_index_type.declaration_code("")
1602 else:
1603 return ""
1605 def generate_subexpr_evaluation_code(self, code):
1606 self.base.generate_evaluation_code(code)
1607 if not self.indices:
1608 self.index.generate_evaluation_code(code)
1609 else:
1610 for i in self.indices:
1611 i.generate_evaluation_code(code)
1613 def generate_subexpr_disposal_code(self, code):
1614 self.base.generate_disposal_code(code)
1615 if not self.indices:
1616 self.index.generate_disposal_code(code)
1617 else:
1618 for i in self.indices:
1619 i.generate_disposal_code(code)
1621 def generate_result_code(self, code):
1622 if self.is_buffer_access:
1623 if code.globalstate.directives['nonecheck']:
1624 self.put_nonecheck(code)
1625 self.buffer_ptr_code = self.buffer_lookup_code(code)
1626 if self.type.is_pyobject:
1627 # is_temp is True, so must pull out value and incref it.
1628 code.putln("%s = *%s;" % (self.result(), self.buffer_ptr_code))
1629 code.putln("Py_INCREF((PyObject*)%s);" % self.result())
1630 elif self.type.is_pyobject:
1631 if self.index.type.is_int:
1632 function = "__Pyx_GetItemInt"
1633 index_code = self.index.result()
1634 else:
1635 function = "PyObject_GetItem"
1636 index_code = self.index.py_result()
1637 sign_code = ""
1638 code.putln(
1639 "%s = %s(%s, %s%s); if (!%s) %s" % (
1640 self.result(),
1641 function,
1642 self.base.py_result(),
1643 index_code,
1644 self.index_unsigned_parameter(),
1645 self.result(),
1646 code.error_goto(self.pos)))
1648 def generate_setitem_code(self, value_code, code):
1649 if self.index.type.is_int:
1650 function = "__Pyx_SetItemInt"
1651 index_code = self.index.result()
1652 else:
1653 function = "PyObject_SetItem"
1654 index_code = self.index.py_result()
1655 code.putln(
1656 "if (%s(%s, %s, %s%s) < 0) %s" % (
1657 function,
1658 self.base.py_result(),
1659 index_code,
1660 value_code,
1661 self.index_unsigned_parameter(),
1662 code.error_goto(self.pos)))
1664 def generate_buffer_setitem_code(self, rhs, code, op=""):
1665 # Used from generate_assignment_code and InPlaceAssignmentNode
1666 if code.globalstate.directives['nonecheck']:
1667 self.put_nonecheck(code)
1668 ptrexpr = self.buffer_lookup_code(code)
1669 if self.buffer_type.dtype.is_pyobject:
1670 # Must manage refcounts. Decref what is already there
1671 # and incref what we put in.
1672 ptr = code.funcstate.allocate_temp(self.buffer_type.buffer_ptr_type)
1673 if rhs.is_temp:
1674 rhs_code = code.funcstate.allocate_temp(rhs.type)
1675 else:
1676 rhs_code = rhs.result()
1677 code.putln("%s = %s;" % (ptr, ptrexpr))
1678 code.putln("Py_DECREF(*%s); Py_INCREF(%s);" % (
1679 ptr, rhs_code
1680 ))
1681 code.putln("*%s %s= %s;" % (ptr, op, rhs_code))
1682 if rhs.is_temp:
1683 code.funcstate.release_temp(rhs_code)
1684 code.funcstate.release_temp(ptr)
1685 else:
1686 # Simple case
1687 code.putln("*%s %s= %s;" % (ptrexpr, op, rhs.result()))
1689 def generate_assignment_code(self, rhs, code):
1690 self.generate_subexpr_evaluation_code(code)
1691 if self.is_buffer_access:
1692 self.generate_buffer_setitem_code(rhs, code)
1693 elif self.type.is_pyobject:
1694 self.generate_setitem_code(rhs.py_result(), code)
1695 else:
1696 code.putln(
1697 "%s = %s;" % (
1698 self.result(), rhs.result()))
1699 self.generate_subexpr_disposal_code(code)
1700 rhs.generate_disposal_code(code)
1702 def generate_deletion_code(self, code):
1703 self.generate_subexpr_evaluation_code(code)
1704 #if self.type.is_pyobject:
1705 if self.index.type.is_int:
1706 function = "PySequence_DelItem"
1707 index_code = self.index.result()
1708 else:
1709 function = "PyObject_DelItem"
1710 index_code = self.index.py_result()
1711 code.putln(
1712 "if (%s(%s, %s) < 0) %s" % (
1713 function,
1714 self.base.py_result(),
1715 index_code,
1716 code.error_goto(self.pos)))
1717 self.generate_subexpr_disposal_code(code)
1719 def buffer_lookup_code(self, code):
1720 # Assign indices to temps
1721 index_temps = [code.funcstate.allocate_temp(i.type) for i in self.indices]
1722 for temp, index in zip(index_temps, self.indices):
1723 code.putln("%s = %s;" % (temp, index.result()))
1724 # Generate buffer access code using these temps
1725 import Buffer
1726 # The above could happen because child_attrs is wrong somewhere so that
1727 # options are not propagated.
1728 return Buffer.put_buffer_lookup_code(entry=self.base.entry,
1729 index_signeds=[i.type.signed for i in self.indices],
1730 index_cnames=index_temps,
1731 options=code.globalstate.directives,
1732 pos=self.pos, code=code)
1734 def put_nonecheck(self, code):
1735 code.globalstate.use_utility_code(raise_noneindex_error_utility_code)
1736 code.putln("if (%s) {" % code.unlikely("%s == Py_None") % self.base.result_as(PyrexTypes.py_object_type))
1737 code.putln("__Pyx_RaiseNoneIndexingError();")
1738 code.putln(code.error_goto(self.pos))
1739 code.putln("}")
1741 class SliceIndexNode(ExprNode):
1742 # 2-element slice indexing
1744 # base ExprNode
1745 # start ExprNode or None
1746 # stop ExprNode or None
1748 subexprs = ['base', 'start', 'stop']
1750 def compile_time_value(self, denv):
1751 base = self.base.compile_time_value(denv)
1752 start = self.start.compile_time_value(denv)
1753 stop = self.stop.compile_time_value(denv)
1754 try:
1755 return base[start:stop]
1756 except Exception, e:
1757 self.compile_time_value_error(e)
1759 def analyse_target_declaration(self, env):
1760 pass
1762 def analyse_types(self, env):
1763 self.base.analyse_types(env)
1764 if self.start:
1765 self.start.analyse_types(env)
1766 if self.stop:
1767 self.stop.analyse_types(env)
1768 self.base = self.base.coerce_to_pyobject(env)
1769 c_int = PyrexTypes.c_py_ssize_t_type
1770 if self.start:
1771 self.start = self.start.coerce_to(c_int, env)
1772 if self.stop:
1773 self.stop = self.stop.coerce_to(c_int, env)
1774 self.type = py_object_type
1775 self.gil_check(env)
1776 self.is_temp = 1
1778 gil_message = "Slicing Python object"
1780 def generate_result_code(self, code):
1781 code.putln(
1782 "%s = PySequence_GetSlice(%s, %s, %s); %s" % (
1783 self.result(),
1784 self.base.py_result(),
1785 self.start_code(),
1786 self.stop_code(),
1787 code.error_goto_if_null(self.result(), self.pos)))
1789 def generate_assignment_code(self, rhs, code):
1790 self.generate_subexpr_evaluation_code(code)
1791 code.put_error_if_neg(self.pos,
1792 "PySequence_SetSlice(%s, %s, %s, %s)" % (
1793 self.base.py_result(),
1794 self.start_code(),
1795 self.stop_code(),
1796 rhs.result()))
1797 self.generate_subexpr_disposal_code(code)
1798 rhs.generate_disposal_code(code)
1800 def generate_deletion_code(self, code):
1801 self.generate_subexpr_evaluation_code(code)
1802 code.put_error_if_neg(self.pos,
1803 "PySequence_DelSlice(%s, %s, %s)" % (
1804 self.base.py_result(),
1805 self.start_code(),
1806 self.stop_code()))
1807 self.generate_subexpr_disposal_code(code)
1809 def start_code(self):
1810 if self.start:
1811 return self.start.result()
1812 else:
1813 return "0"
1815 def stop_code(self):
1816 if self.stop:
1817 return self.stop.result()
1818 else:
1819 return "PY_SSIZE_T_MAX"
1821 def calculate_result_code(self):
1822 # self.result() is not used, but this method must exist
1823 return "<unused>"
1826 class SliceNode(ExprNode):
1827 # start:stop:step in subscript list
1829 # start ExprNode
1830 # stop ExprNode
1831 # step ExprNode
1833 def compile_time_value(self, denv):
1834 start = self.start.compile_time_value(denv)
1835 stop = self.stop.compile_time_value(denv)
1836 step = step.step.compile_time_value(denv)
1837 try:
1838 return slice(start, stop, step)
1839 except Exception, e:
1840 self.compile_time_value_error(e)
1842 subexprs = ['start', 'stop', 'step']
1844 def analyse_types(self, env):
1845 self.start.analyse_types(env)
1846 self.stop.analyse_types(env)
1847 self.step.analyse_types(env)
1848 self.start = self.start.coerce_to_pyobject(env)
1849 self.stop = self.stop.coerce_to_pyobject(env)
1850 self.step = self.step.coerce_to_pyobject(env)
1851 self.type = py_object_type
1852 self.gil_check(env)
1853 self.is_temp = 1
1855 gil_message = "Constructing Python slice object"
1857 def generate_result_code(self, code):
1858 code.putln(
1859 "%s = PySlice_New(%s, %s, %s); %s" % (
1860 self.result(),
1861 self.start.py_result(),
1862 self.stop.py_result(),
1863 self.step.py_result(),
1864 code.error_goto_if_null(self.result(), self.pos)))
1867 class CallNode(ExprNode):
1868 def gil_check(self, env):
1869 # Make sure we're not in a nogil environment
1870 if env.nogil:
1871 error(self.pos, "Calling gil-requiring function without gil")
1873 def analyse_as_type_constructor(self, env):
1874 type = self.function.analyse_as_type(env)
1875 if type and type.is_struct_or_union:
1876 args, kwds = self.explicit_args_kwds()
1877 items = []
1878 for arg, member in zip(args, type.scope.var_entries):
1879 items.append(DictItemNode(pos=arg.pos, key=NameNode(pos=arg.pos, name=member.name), value=arg))
1880 if kwds:
1881 items += kwds.key_value_pairs
1882 self.key_value_pairs = items
1883 self.__class__ = DictNode
1884 self.analyse_types(env)
1885 self.coerce_to(type, env)
1886 return True
1889 class SimpleCallNode(CallNode):
1890 # Function call without keyword, * or ** args.
1892 # function ExprNode
1893 # args [ExprNode]
1894 # arg_tuple ExprNode or None used internally
1895 # self ExprNode or None used internally
1896 # coerced_self ExprNode or None used internally
1897 # wrapper_call bool used internally
1898 # has_optional_args bool used internally
1900 subexprs = ['self', 'coerced_self', 'function', 'args', 'arg_tuple']
1902 self = None
1903 coerced_self = None
1904 arg_tuple = None
1905 wrapper_call = False
1906 has_optional_args = False
1908 def compile_time_value(self, denv):
1909 function = self.function.compile_time_value(denv)
1910 args = [arg.compile_time_value(denv) for arg in self.args]
1911 try:
1912 return function(*args)
1913 except Exception, e:
1914 self.compile_time_value_error(e)
1916 def analyse_as_type(self, env):
1917 attr = self.function.as_cython_attribute()
1918 if attr == 'pointer':
1919 if len(self.args) != 1:
1920 error(self.args.pos, "only one type allowed.")
1921 else:
1922 type = self.args[0].analyse_as_type(env)
1923 if not type:
1924 error(self.args[0].pos, "Unknown type")
1925 else:
1926 return PyrexTypes.CPtrType(type)
1928 def explicit_args_kwds(self):
1929 return self.args, None
1931 def analyse_types(self, env):
1932 if self.analyse_as_type_constructor(env):
1933 return
1934 function = self.function
1935 function.is_called = 1
1936 self.function.analyse_types(env)
1937 if function.is_attribute and function.is_py_attr and \
1938 function.attribute == "append" and len(self.args) == 1:
1939 # L.append(x) is almost always applied to a list
1940 self.py_func = self.function
1941 self.function = NameNode(pos=self.function.pos, name="__Pyx_PyObject_Append")
1942 self.function.analyse_types(env)
1943 self.self = self.py_func.obj
1944 function.obj = CloneNode(self.self)
1945 env.use_utility_code(append_utility_code)
1946 if function.is_attribute and function.entry and function.entry.is_cmethod:
1947 # Take ownership of the object from which the attribute
1948 # was obtained, because we need to pass it as 'self'.
1949 self.self = function.obj
1950 function.obj = CloneNode(self.self)
1951 func_type = self.function_type()
1952 if func_type.is_pyobject:
1953 self.arg_tuple = TupleNode(self.pos, args = self.args)
1954 self.arg_tuple.analyse_types(env)
1955 self.args = None
1956 self.type = py_object_type
1957 self.gil_check(env)
1958 self.is_temp = 1
1959 else:
1960 for arg in self.args:
1961 arg.analyse_types(env)
1962 if self.self and func_type.args:
1963 # Coerce 'self' to the type expected by the method.
1964 expected_type = func_type.args[0].type
1965 self.coerced_self = CloneNode(self.self).coerce_to(
1966 expected_type, env)
1967 # Insert coerced 'self' argument into argument list.
1968 self.args.insert(0, self.coerced_self)
1969 self.analyse_c_function_call(env)
1971 def function_type(self):
1972 # Return the type of the function being called, coercing a function
1973 # pointer to a function if necessary.
1974 func_type = self.function.type
1975 if func_type.is_ptr:
1976 func_type = func_type.base_type
1977 return func_type
1979 def analyse_c_function_call(self, env):
1980 func_type = self.function_type()
1981 # Check function type
1982 if not func_type.is_cfunction:
1983 if not func_type.is_error:
1984 error(self.pos, "Calling non-function type '%s'" %
1985 func_type)
1986 self.type = PyrexTypes.error_type
1987 self.result_code = "<error>"
1988 return
1989 # Check no. of args
1990 max_nargs = len(func_type.args)
1991 expected_nargs = max_nargs - func_type.optional_arg_count
1992 actual_nargs = len(self.args)
1993 if actual_nargs < expected_nargs \
1994 or (not func_type.has_varargs and actual_nargs > max_nargs):
1995 expected_str = str(expected_nargs)
1996 if func_type.has_varargs:
1997 expected_str = "at least " + expected_str
1998 elif func_type.optional_arg_count:
1999 if actual_nargs < max_nargs:
2000 expected_str = "at least " + expected_str
2001 else:
2002 expected_str = "at most " + str(max_nargs)
2003 error(self.pos,
2004 "Call with wrong number of arguments (expected %s, got %s)"
2005 % (expected_str, actual_nargs))
2006 self.args = None
2007 self.type = PyrexTypes.error_type
2008 self.result_code = "<error>"
2009 return
2010 if func_type.optional_arg_count and expected_nargs != actual_nargs:
2011 self.has_optional_args = 1
2012 self.is_temp = 1
2013 self.opt_arg_struct = env.allocate_temp(func_type.op_arg_struct.base_type)
2014 env.release_temp(self.opt_arg_struct)
2015 # Coerce arguments
2016 for i in range(min(max_nargs, actual_nargs)):
2017 formal_type = func_type.args[i].type
2018 self.args[i] = self.args[i].coerce_to(formal_type, env)
2019 for i in range(max_nargs, actual_nargs):
2020 if self.args[i].type.is_pyobject:
2021 error(self.args[i].pos,
2022 "Python object cannot be passed as a varargs parameter")
2023 # Calc result type and code fragment
2024 self.type = func_type.return_type
2025 if self.type.is_pyobject \
2026 or func_type.exception_value is not None \
2027 or func_type.exception_check:
2028 self.is_temp = 1
2029 if self.type.is_pyobject:
2030 self.result_ctype = py_object_type
2031 # C++ exception handler
2032 if func_type.exception_check == '+':
2033 if func_type.exception_value is None:
2034 env.use_utility_code(cpp_exception_utility_code)
2035 # Check gil
2036 if not func_type.nogil:
2037 self.gil_check(env)
2039 def calculate_result_code(self):
2040 return self.c_call_code()
2042 def c_call_code(self):
2043 func_type = self.function_type()
2044 if self.args is None or not func_type.is_cfunction:
2045 return "<error>"
2046 formal_args = func_type.args
2047 arg_list_code = []
2048 args = zip(formal_args, self.args)
2049 max_nargs = len(func_type.args)
2050 expected_nargs = max_nargs - func_type.optional_arg_count
2051 actual_nargs = len(self.args)
2052 for formal_arg, actual_arg in args[:expected_nargs]:
2053 arg_code = actual_arg.result_as(formal_arg.type)
2054 arg_list_code.append(arg_code)
2056 if func_type.is_overridable:
2057 arg_list_code.append(str(int(self.wrapper_call or self.function.entry.is_unbound_cmethod)))
2059 if func_type.optional_arg_count:
2060 if expected_nargs == actual_nargs:
2061 optional_args = 'NULL'
2062 else:
2063 optional_args = "&%s" % self.opt_arg_struct
2064 arg_list_code.append(optional_args)
2066 for actual_arg in self.args[len(formal_args):]:
2067 arg_list_code.append(actual_arg.result())
2068 result = "%s(%s)" % (self.function.result(),
2069 join(arg_list_code, ", "))
2070 # if self.wrapper_call or \
2071 # self.function.entry.is_unbound_cmethod and self.function.entry.type.is_overridable:
2072 # result = "(%s = 1, %s)" % (Naming.skip_dispatch_cname, result)
2073 return result
2075 def generate_result_code(self, code):
2076 func_type = self.function_type()
2077 if func_type.is_pyobject:
2078 arg_code = self.arg_tuple.py_result()
2079 code.putln(
2080 "%s = PyObject_Call(%s, %s, NULL); %s" % (
2081 self.result(),
2082 self.function.py_result(),
2083 arg_code,
2084 code.error_goto_if_null(self.result(), self.pos)))
2085 elif func_type.is_cfunction:
2086 if self.has_optional_args:
2087 actual_nargs = len(self.args)
2088 expected_nargs = len(func_type.args) - func_type.optional_arg_count
2089 code.putln("%s.%s = %s;" % (
2090 self.opt_arg_struct,
2091 Naming.pyrex_prefix + "n",
2092 len(self.args) - expected_nargs))
2093 args = zip(func_type.args, self.args)
2094 for formal_arg, actual_arg in args[expected_nargs:actual_nargs]:
2095 code.putln("%s.%s = %s;" % (
2096 self.opt_arg_struct,
2097 formal_arg.name,
2098 actual_arg.result_as(formal_arg.type)))
2099 exc_checks = []
2100 if self.type.is_pyobject:
2101 exc_checks.append("!%s" % self.result())
2102 else:
2103 exc_val = func_type.exception_value
2104 exc_check = func_type.exception_check
2105 if exc_val is not None:
2106 exc_checks.append("%s == %s" % (self.result(), exc_val))
2107 if exc_check:
2108 exc_checks.append("PyErr_Occurred()")
2109 if self.is_temp or exc_checks:
2110 rhs = self.c_call_code()
2111 if self.result():
2112 lhs = "%s = " % self.result()
2113 if self.is_temp and self.type.is_pyobject:
2114 #return_type = self.type # func_type.return_type
2115 #print "SimpleCallNode.generate_result_code: casting", rhs, \
2116 # "from", return_type, "to pyobject" ###
2117 rhs = typecast(py_object_type, self.type, rhs)
2118 else:
2119 lhs = ""
2120 if func_type.exception_check == '+':
2121 if func_type.exception_value is None:
2122 raise_py_exception = "__Pyx_CppExn2PyErr()"
2123 elif func_type.exception_value.type.is_pyobject:
2124 raise_py_exception = 'PyErr_SetString(%s, "")' % func_type.exception_value.entry.cname
2125 else:
2126 raise_py_exception = '%s(); if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError , "Error converting c++ exception.")' % func_type.exception_value.entry.cname
2127 code.putln(
2128 "try {%s%s;} catch(...) {%s; %s}" % (
2129 lhs,
2130 rhs,
2131 raise_py_exception,
2132 code.error_goto(self.pos)))
2133 else:
2134 if exc_checks:
2135 goto_error = code.error_goto_if(" && ".join(exc_checks), self.pos)
2136 else:
2137 goto_error = ""
2138 code.putln("%s%s; %s" % (lhs, rhs, goto_error))
2140 class GeneralCallNode(CallNode):
2141 # General Python function call, including keyword,
2142 # * and ** arguments.
2144 # function ExprNode
2145 # positional_args ExprNode Tuple of positional arguments
2146 # keyword_args ExprNode or None Dict of keyword arguments
2147 # starstar_arg ExprNode or None Dict of extra keyword args
2149 subexprs = ['function', 'positional_args', 'keyword_args', 'starstar_arg']
2151 def compile_time_value(self, denv):
2152 function = self.function.compile_time_value(denv)
2153 positional_args = self.positional_args.compile_time_value(denv)
2154 keyword_args = self.keyword_args.compile_time_value(denv)
2155 starstar_arg = self.starstar_arg.compile_time_value(denv)
2156 try:
2157 keyword_args.update(starstar_arg)
2158 return function(*positional_args, **keyword_args)
2159 except Exception, e:
2160 self.compile_time_value_error(e)
2162 def explicit_args_kwds(self):
2163 if self.starstar_arg or not isinstance(self.positional_args, TupleNode):
2164 raise PostParseError(self.pos,
2165 'Compile-time keyword arguments must be explicit.')
2166 return self.positional_args.args, self.keyword_args
2168 def analyse_types(self, env):
2169 if self.analyse_as_type_constructor(env):
2170 return
2171 self.function.analyse_types(env)
2172 self.positional_args.analyse_types(env)
2173 if self.keyword_args:
2174 self.keyword_args.analyse_types(env)
2175 if self.starstar_arg:
2176 self.starstar_arg.analyse_types(env)
2177 self.function = self.function.coerce_to_pyobject(env)
2178 self.positional_args = \
2179 self.positional_args.coerce_to_pyobject(env)
2180 if self.starstar_arg:
2181 self.starstar_arg = \
2182 self.starstar_arg.coerce_to_pyobject(env)
2183 self.type = py_object_type
2184 self.gil_check(env)
2185 self.is_temp = 1
2187 def generate_result_code(self, code):
2188 if self.keyword_args and self.starstar_arg:
2189 code.put_error_if_neg(self.pos,
2190 "PyDict_Update(%s, %s)" % (
2191 self.keyword_args.py_result(),
2192 self.starstar_arg.py_result()))
2193 keyword_code = self.keyword_args.py_result()
2194 elif self.keyword_args:
2195 keyword_code = self.keyword_args.py_result()
2196 elif self.starstar_arg:
2197 keyword_code = self.starstar_arg.py_result()
2198 else:
2199 keyword_code = None
2200 if not keyword_code:
2201 call_code = "PyObject_Call(%s, %s, NULL)" % (
2202 self.function.py_result(),
2203 self.positional_args.py_result())
2204 else:
2205 call_code = "PyEval_CallObjectWithKeywords(%s, %s, %s)" % (
2206 self.function.py_result(),
2207 self.positional_args.py_result(),
2208 keyword_code)
2209 code.putln(
2210 "%s = %s; %s" % (
2211 self.result(),
2212 call_code,
2213 code.error_goto_if_null(self.result(), self.pos)))
2216 class AsTupleNode(ExprNode):
2217 # Convert argument to tuple. Used for normalising
2218 # the * argument of a function call.
2220 # arg ExprNode
2222 subexprs = ['arg']
2224 def compile_time_value(self, denv):
2225 arg = self.arg.compile_time_value(denv)
2226 try:
2227 return tuple(arg)
2228 except Exception, e:
2229 self.compile_time_value_error(e)
2231 def analyse_types(self, env):
2232 self.arg.analyse_types(env)
2233 self.arg = self.arg.coerce_to_pyobject(env)
2234 self.type = py_object_type
2235 self.gil_check(env)
2236 self.is_temp = 1
2238 gil_message = "Constructing Python tuple"
2240 def generate_result_code(self, code):
2241 code.putln(
2242 "%s = PySequence_Tuple(%s); %s" % (
2243 self.result(),
2244 self.arg.py_result(),
2245 code.error_goto_if_null(self.result(), self.pos)))
2248 class AttributeNode(ExprNode):
2249 # obj.attribute
2251 # obj ExprNode
2252 # attribute string
2253 # needs_none_check boolean Used if obj is an extension type.
2254 # If set to True, it is known that the type is not None.
2256 # Used internally:
2258 # is_py_attr boolean Is a Python getattr operation
2259 # member string C name of struct member
2260 # is_called boolean Function call is being done on result
2261 # entry Entry Symbol table entry of attribute
2262 # interned_attr_cname string C name of interned attribute name
2264 is_attribute = 1
2265 subexprs = ['obj']
2267 type = PyrexTypes.error_type
2268 entry = None
2269 is_called = 0
2270 needs_none_check = True
2272 def as_cython_attribute(self):
2273 if isinstance(self.obj, NameNode) and self.obj.is_cython_module:
2274 return self.attribute
2276 def coerce_to(self, dst_type, env):
2277 # If coercing to a generic pyobject and this is a cpdef function
2278 # we can create the corresponding attribute
2279 if dst_type is py_object_type:
2280 entry = self.entry
2281 if entry and entry.is_cfunction and entry.as_variable:
2282 # must be a cpdef function
2283 self.is_temp = 1
2284 self.entry = entry.as_variable
2285 self.analyse_as_python_attribute(env)
2286 return self
2287 return ExprNode.coerce_to(self, dst_type, env)
2289 def compile_time_value(self, denv):
2290 attr = self.attribute
2291 if attr.beginswith("__") and attr.endswith("__"):
2292 self.error("Invalid attribute name '%s' in compile-time expression"
2293 % attr)
2294 return None
2295 obj = self.arg.compile_time_value(denv)
2296 try:
2297 return getattr(obj, attr)
2298 except Exception, e:
2299 self.compile_time_value_error(e)
2301 def analyse_target_declaration(self, env):
2302 pass
2304 def analyse_target_types(self, env):
2305 self.analyse_types(env, target = 1)
2307 def analyse_types(self, env, target = 0):
2308 if self.analyse_as_cimported_attribute(env, target):
2309 return
2310 if not target and self.analyse_as_unbound_cmethod(env):
2311 return
2312 self.analyse_as_ordinary_attribute(env, target)
2314 def analyse_as_cimported_attribute(self, env, target):
2315 # Try to interpret this as a reference to an imported
2316 # C const, type, var or function. If successful, mutates
2317 # this node into a NameNode and returns 1, otherwise
2318 # returns 0.
2319 module_scope = self.obj.analyse_as_module(env)
2320 if module_scope:
2321 entry = module_scope.lookup_here(self.attribute)
2322 if entry and (
2323 entry.is_cglobal or entry.is_cfunction
2324 or entry.is_type or entry.is_const):
2325 self.mutate_into_name_node(env, entry, target)
2326 return 1
2327 return 0
2329 def analyse_as_unbound_cmethod(self, env):
2330 # Try to interpret this as a reference to an unbound
2331 # C method of an extension type. If successful, mutates
2332 # this node into a NameNode and returns 1, otherwise
2333 # returns 0.
2334 type = self.obj.analyse_as_extension_type(env)
2335 if type:
2336 entry = type.scope.lookup_here(self.attribute)
2337 if entry and entry.is_cmethod:
2338 # Create a temporary entry describing the C method
2339 # as an ordinary function.
2340 ubcm_entry = Symtab.Entry(entry.name,
2341 "%s->%s" % (type.vtabptr_cname, entry.cname),
2342 entry.type)
2343 ubcm_entry.is_cfunction = 1
2344 ubcm_entry.func_cname = entry.func_cname
2345 ubcm_entry.is_unbound_cmethod = 1
2346 self.mutate_into_name_node(env, ubcm_entry, None)
2347 return 1
2348 return 0
2350 def analyse_as_type(self, env):
2351 module_scope = self.obj.analyse_as_module(env)
2352 if module_scope:
2353 return module_scope.lookup_type(self.attribute)
2354 return None
2356 def analyse_as_extension_type(self, env):
2357 # Try to interpret this as a reference to an extension type
2358 # in a cimported module. Returns the extension type, or None.
2359 module_scope = self.obj.analyse_as_module(env)
2360 if module_scope:
2361 entry = module_scope.lookup_here(self.attribute)
2362 if entry and entry.is_type and entry.type.is_extension_type:
2363 return entry.type
2364 return None
2366 def analyse_as_module(self, env):
2367 # Try to interpret this as a reference to a cimported module
2368 # in another cimported module. Returns the module scope, or None.
2369 module_scope = self.obj.analyse_as_module(env)
2370 if module_scope:
2371 entry = module_scope.lookup_here(self.attribute)
2372 if entry and entry.as_module:
2373 return entry.as_module
2374 return None
2376 def mutate_into_name_node(self, env, entry, target):
2377 # Mutate this node into a NameNode and complete the
2378 # analyse_types phase.
2379 self.__class__ = NameNode
2380 self.name = self.attribute
2381 self.entry = entry
2382 del self.obj
2383 del self.attribute
2384 if target:
2385 NameNode.analyse_target_types(self, env)
2386 else:
2387 NameNode.analyse_rvalue_entry(self, env)
2389 def analyse_as_ordinary_attribute(self, env, target):
2390 self.obj.analyse_types(env)
2391 self.analyse_attribute(env)
2392 if self.entry and self.entry.is_cmethod and not self.is_called:
2393 # error(self.pos, "C method can only be called")
2394 pass
2395 ## Reference to C array turns into pointer to first element.
2396 #while self.type.is_array:
2397 # self.type = self.type.element_ptr_type()
2398 if self.is_py_attr:
2399 if not target:
2400 self.is_temp = 1
2401 self.result_ctype = py_object_type
2403 def analyse_attribute(self, env):
2404 # Look up attribute and set self.type and self.member.
2405 self.is_py_attr = 0
2406 self.member = self.attribute
2407 if self.obj.type.is_string:
2408 self.obj = self.obj.coerce_to_pyobject(env)
2409 obj_type = self.obj.type
2410 if obj_type.is_ptr or obj_type.is_array:
2411 obj_type = obj_type.base_type
2412 self.op = "->"
2413 elif obj_type.is_extension_type:
2414 self.op = "->"
2415 else:
2416 self.op = "."
2417 if obj_type.has_attributes:
2418 entry = None
2419 if obj_type.attributes_known():
2420 entry = obj_type.scope.lookup_here(self.attribute)
2421 if entry and entry.is_member:
2422 entry = None
2423 else:
2424 error(self.pos,
2425 "Cannot select attribute of incomplete type '%s'"
2426 % obj_type)
2427 self.type = PyrexTypes.error_type
2428 return
2429 self.entry = entry
2430 if entry:
2431 if obj_type.is_extension_type and entry.name == "__weakref__":
2432 error(self.pos, "Illegal use of special attribute __weakref__")
2433 # methods need the normal attribute lookup
2434 # because they do not have struct entries
2435 if entry.is_variable or entry.is_cmethod:
2436 self.type = entry.type
2437 self.member = entry.cname
2438 return
2439 else:
2440 # If it's not a variable or C method, it must be a Python
2441 # method of an extension type, so we treat it like a Python
2442 # attribute.
2443 pass
2444 # If we get here, the base object is not a struct/union/extension
2445 # type, or it is an extension type and the attribute is either not
2446 # declared or is declared as a Python method. Treat it as a Python
2447 # attribute reference.
2448 self.analyse_as_python_attribute(env)
2450 def analyse_as_python_attribute(self, env):
2451 obj_type = self.obj.type
2452 self.member = self.attribute
2453 if obj_type.is_pyobject:
2454 self.type = py_object_type
2455 self.is_py_attr = 1
2456 self.interned_attr_cname = env.intern_identifier(self.attribute)
2457 self.gil_check(env)
2458 else:
2459 if not obj_type.is_error:
2460 error(self.pos,
2461 "Object of type '%s' has no attribute '%s'" %
2462 (obj_type, self.attribute))
2464 gil_message = "Accessing Python attribute"
2466 def is_simple(self):
2467 if self.obj:
2468 return self.result_in_temp() or self.obj.is_simple()
2469 else:
2470 return NameNode.is_simple(self)
2472 def is_lvalue(self):
2473 if self.obj:
2474 return 1
2475 else:
2476 return NameNode.is_lvalue(self)
2478 def is_ephemeral(self):
2479 if self.obj:
2480 return self.obj.is_ephemeral()
2481 else:
2482 return NameNode.is_ephemeral(self)
2484 def calculate_result_code(self):
2485 #print "AttributeNode.calculate_result_code:", self.member ###
2486 #print "...obj node =", self.obj, "code", self.obj.result() ###
2487 #print "...obj type", self.obj.type, "ctype", self.obj.ctype() ###
2488 obj = self.obj
2489 obj_code = obj.result_as(obj.type)
2490 #print "...obj_code =", obj_code ###
2491 if self.entry and self.entry.is_cmethod:
2492 if obj.type.is_extension_type:
2493 return "((struct %s *)%s%s%s)->%s" % (
2494 obj.type.vtabstruct_cname, obj_code, self.op,
2495 obj.type.vtabslot_cname, self.member)
2496 else:
2497 return self.member
2498 else:
2499 return "%s%s%s" % (obj_code, self.op, self.member)
2501 def generate_result_code(self, code):
2502 if self.is_py_attr:
2503 code.putln(
2504 '%s = PyObject_GetAttr(%s, %s); %s' % (
2505 self.result(),
2506 self.obj.py_result(),
2507 self.interned_attr_cname,
2508 code.error_goto_if_null(self.result(), self.pos)))
2509 else:
2510 # result_code contains what is needed, but we may need to insert
2511 # a check and raise an exception
2512 if (self.obj.type.is_extension_type
2513 and self.needs_none_check
2514 and code.globalstate.directives['nonecheck']):
2515 self.put_nonecheck(code)
2517 def generate_assignment_code(self, rhs, code):
2518 self.obj.generate_evaluation_code(code)
2519 if self.is_py_attr:
2520 code.put_error_if_neg(self.pos,
2521 'PyObject_SetAttr(%s, %s, %s)' % (
2522 self.obj.py_result(),
2523 self.interned_attr_cname,
2524 rhs.py_result()))
2525 rhs.generate_disposal_code(code)
2526 else:
2527 if (self.obj.type.is_extension_type
2528 and self.needs_none_check
2529 and code.globalstate.directives['nonecheck']):
2530 self.put_nonecheck(code)
2532 select_code = self.result()
2533 if self.type.is_pyobject:
2534 rhs.make_owned_reference(code)
2535 code.put_decref(select_code, self.ctype())
2536 code.putln(
2537 "%s = %s;" % (
2538 select_code,
2539 rhs.result_as(self.ctype())))
2540 #rhs.result()))
2541 rhs.generate_post_assignment_code(code)
2542 self.obj.generate_disposal_code(code)
2544 def generate_deletion_code(self, code):
2545 self.obj.generate_evaluation_code(code)
2546 if self.is_py_attr:
2547 code.put_error_if_neg(self.pos,
2548 'PyObject_DelAttr(%s, %s)' % (
2549 self.obj.py_result(),
2550 self.interned_attr_cname))
2551 else:
2552 error(self.pos, "Cannot delete C attribute of extension type")
2553 self.obj.generate_disposal_code(code)
2555 def annotate(self, code):
2556 if self.is_py_attr:
2557 code.annotate(self.pos, AnnotationItem('py_attr', 'python attribute', size=len(self.attribute)))
2558 else:
2559 code.annotate(self.pos, AnnotationItem('c_attr', 'c attribute', size=len(self.attribute)))
2561 def put_nonecheck(self, code):
2562 code.globalstate.use_utility_code(raise_noneattr_error_utility_code)
2563 code.putln("if (%s) {" % code.unlikely("%s == Py_None") % self.obj.result_as(PyrexTypes.py_object_type))
2564 code.putln("__Pyx_RaiseNoneAttributeError(\"%s\");" % self.attribute.encode("UTF-8")) # todo: fix encoding
2565 code.putln(code.error_goto(self.pos))
2566 code.putln("}")
2569 #-------------------------------------------------------------------
2571 # Constructor nodes
2573 #-------------------------------------------------------------------
2575 class SequenceNode(ExprNode):
2576 # Base class for list and tuple constructor nodes.
2577 # Contains common code for performing sequence unpacking.
2579 # args [ExprNode]
2580 # iterator ExprNode
2581 # unpacked_items [ExprNode] or None
2582 # coerced_unpacked_items [ExprNode] or None
2584 subexprs = ['args']
2586 is_sequence_constructor = 1
2587 unpacked_items = None
2589 def compile_time_value_list(self, denv):
2590 return [arg.compile_time_value(denv) for arg in self.args]
2592 def analyse_target_declaration(self, env):
2593 for arg in self.args:
2594 arg.analyse_target_declaration(env)
2596 def analyse_types(self, env, skip_children=False):
2597 for i in range(len(self.args)):
2598 arg = self.args[i]
2599 if not skip_children: arg.analyse_types(env)
2600 self.args[i] = arg.coerce_to_pyobject(env)
2601 self.type = py_object_type
2602 self.gil_check(env)
2603 self.is_temp = 1
2605 def analyse_target_types(self, env):
2606 self.iterator = PyTempNode(self.pos, env)
2607 self.unpacked_items = []
2608 self.coerced_unpacked_items = []
2609 for arg in self.args:
2610 arg.analyse_target_types(env)
2611 unpacked_item = PyTempNode(self.pos, env)
2612 coerced_unpacked_item = unpacked_item.coerce_to(arg.type, env)
2613 self.unpacked_items.append(unpacked_item)
2614 self.coerced_unpacked_items.append(coerced_unpacked_item)
2615 self.type = py_object_type
2616 env.use_utility_code(unpacking_utility_code)
2618 def allocate_target_temps(self, env, rhs):
2619 self.iterator.allocate_temps(env)
2620 for arg, node in zip(self.args, self.coerced_unpacked_items):
2621 node.allocate_temps(env)
2622 arg.allocate_target_temps(env, node)
2623 #arg.release_target_temp(env)
2624 #node.release_temp(env)
2625 if rhs:
2626 rhs.release_temp(env)
2627 self.iterator.release_temp(env)
2629 # def release_target_temp(self, env):
2630 # #for arg in self.args:
2631 # # arg.release_target_temp(env)
2632 # #for node in self.coerced_unpacked_items:
2633 # # node.release_temp(env)
2634 # self.iterator.release_temp(env)
2636 def generate_result_code(self, code):
2637 self.generate_operation_code(code)
2639 def generate_assignment_code(self, rhs, code):
2640 code.putln(
2641 "if (PyTuple_CheckExact(%s) && PyTuple_GET_SIZE(%s) == %s) {" % (
2642 rhs.py_result(),
2643 rhs.py_result(),
2644 len(self.args)))
2645 code.putln("PyObject* tuple = %s;" % rhs.py_result())
2646 for i in range(len(self.args)):
2647 item = self.unpacked_items[i]
2648 code.putln(
2649 "%s = PyTuple_GET_ITEM(tuple, %s);" % (
2650 item.result(),
2651 i))
2652 code.put_incref(item.result(), item.ctype())
2653 value_node = self.coerced_unpacked_items[i]
2654 value_node.generate_evaluation_code(code)
2655 self.args[i].generate_assignment_code(value_node, code)
2657 rhs.generate_disposal_code(code)
2658 code.putln("}")
2659 code.putln("else {")
2661 code.putln(
2662 "%s = PyObject_GetIter(%s); %s" % (
2663 self.iterator.result(),
2664 rhs.py_result(),
2665 code.error_goto_if_null(self.iterator.result(), self.pos)))
2666 rhs.generate_disposal_code(code)
2667 for i in range(len(self.args)):
2668 item = self.unpacked_items[i]
2669 unpack_code = "__Pyx_UnpackItem(%s, %d)" % (
2670 self.iterator.py_result(), i)
2671 code.putln(
2672 "%s = %s; %s" % (
2673 item.result(),
2674 typecast(item.ctype(), py_object_type, unpack_code),
2675 code.error_goto_if_null(item.result(), self.pos)))
2676 value_node = self.coerced_unpacked_items[i]
2677 value_node.generate_evaluation_code(code)
2678 self.args[i].generate_assignment_code(value_node, code)
2679 code.put_error_if_neg(self.pos,
2680 "__Pyx_EndUnpack(%s)" % (
2681 self.iterator.py_result()))
2682 if debug_disposal_code:
2683 print("UnpackNode.generate_assignment_code:")
2684 print("...generating disposal code for %s" % self.iterator)
2685 self.iterator.generate_disposal_code(code)
2687 code.putln("}")
2689 def annotate(self, code):
2690 for arg in self.args:
2691 arg.annotate(code)
2692 if self.unpacked_items:
2693 for arg in self.unpacked_items:
2694 arg.annotate(code)
2695 for arg in self.coerced_unpacked_items:
2696 arg.annotate(code)
2699 class TupleNode(SequenceNode):
2700 # Tuple constructor.
2702 gil_message = "Constructing Python tuple"
2704 def analyse_types(self, env, skip_children=False):
2705 if len(self.args) == 0:
2706 self.is_temp = 0
2707 self.is_literal = 1
2708 else:
2709 SequenceNode.analyse_types(self, env, skip_children)
2710 self.type = tuple_type
2712 def calculate_result_code(self):
2713 if len(self.args) > 0:
2714 error(self.pos, "Positive length tuples must be constructed.")
2715 else:
2716 return Naming.empty_tuple
2718 def compile_time_value(self, denv):
2719 values = self.compile_time_value_list(denv)
2720 try:
2721 return tuple(values)
2722 except Exception, e:
2723 self.compile_time_value_error(e)
2725 def generate_operation_code(self, code):
2726 if len(self.args) == 0:
2727 # result_code is Naming.empty_tuple
2728 return
2729 code.putln(
2730 "%s = PyTuple_New(%s); %s" % (
2731 self.result(),
2732 len(self.args),
2733 code.error_goto_if_null(self.result(), self.pos)))
2734 for i in range(len(self.args)):
2735 arg = self.args[i]
2736 if not arg.result_in_temp():
2737 code.put_incref(arg.result(), arg.ctype())
2738 code.putln(
2739 "PyTuple_SET_ITEM(%s, %s, %s);" % (
2740 self.result(),
2741 i,
2742 arg.py_result()))
2744 def generate_subexpr_disposal_code(self, code):
2745 # We call generate_post_assignment_code here instead
2746 # of generate_disposal_code, because values were stored
2747 # in the tuple using a reference-stealing operation.
2748 for arg in self.args:
2749 arg.generate_post_assignment_code(code)
2752 class ListNode(SequenceNode):
2753 # List constructor.
2755 # obj_conversion_errors [PyrexError] used internally
2756 # orignial_args [ExprNode] used internally
2758 gil_message = "Constructing Python list"
2760 def analyse_expressions(self, env):
2761 ExprNode.analyse_expressions(self, env)
2762 self.coerce_to_pyobject(env)
2764 def analyse_types(self, env):
2765 hold_errors()
2766 self.original_args = list(self.args)
2767 SequenceNode.analyse_types(self, env)
2768 self.type = list_type
2769 self.obj_conversion_errors = held_errors()
2770 release_errors(ignore=True)
2772 def coerce_to(self, dst_type, env):
2773 if dst_type.is_pyobject:
2774 for err in self.obj_conversion_errors:
2775 report_error(err)
2776 self.obj_conversion_errors = []
2777 if not self.type.subtype_of(dst_type):
2778 error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
2779 elif dst_type.is_ptr:
2780 base_type = dst_type.base_type
2781 self.type = PyrexTypes.CArrayType(base_type, len(self.args))
2782 for i in range(len(self.original_args)):
2783 arg = self.args[i]
2784 if isinstance(arg, CoerceToPyTypeNode):
2785 arg = arg.arg
2786 self.args[i] = arg.coerce_to(base_type, env)
2787 elif dst_type.is_struct:
2788 if len(self.args) > len(dst_type.scope.var_entries):
2789 error(self.pos, "Too may members for '%s'" % dst_type)
2790 else:
2791 if len(self.args) < len(dst_type.scope.var_entries):
2792 warning(self.pos, "Too few members for '%s'" % dst_type, 1)
2793 for i, (arg, member) in enumerate(zip(self.original_args, dst_type.scope.var_entries)):
2794 if isinstance(arg, CoerceToPyTypeNode):
2795 arg = arg.arg
2796 self.args[i] = arg.coerce_to(member.type, env)
2797 self.type = dst_type
2798 else:
2799 self.type = error_type
2800 error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
2801 return self
2803 def release_temp(self, env):
2804 if self.type.is_array:
2805 # To be valid C++, we must allocate the memory on the stack
2806 # manually and be sure not to reuse it for something else.
2807 pass
2808 else:
2809 SequenceNode.release_temp(self, env)
2811 def compile_time_value(self, denv):
2812 return self.compile_time_value_list(denv)
2814 def generate_operation_code(self, code):
2815 if self.type.is_pyobject:
2816 for err in self.obj_conversion_errors:
2817 report_error(err)
2818 code.putln("%s = PyList_New(%s); %s" %
2819 (self.result(),
2820 len(self.args),
2821 code.error_goto_if_null(self.result(), self.pos)))
2822 for i in range(len(self.args)):
2823 arg = self.args[i]
2824 #if not arg.is_temp:
2825 if not arg.result_in_temp():
2826 code.put_incref(arg.result(), arg.ctype())
2827 code.putln("PyList_SET_ITEM(%s, %s, %s);" %
2828 (self.result(),
2829 i,
2830 arg.py_result()))
2831 elif self.type.is_array:
2832 for i, arg in enumerate(self.args):
2833 code.putln("%s[%s] = %s;" % (
2834 self.result(),
2835 i,
2836 arg.result()))
2837 elif self.type.is_struct or 1:
2838 for arg, member in zip(self.args, self.type.scope.var_entries):
2839 code.putln("%s.%s = %s;" % (
2840 self.result(),
2841 member.cname,
2842 arg.result()))
2843 else:
2844 raise InternalError("List type never specified")
2846 def generate_subexpr_disposal_code(self, code):
2847 # We call generate_post_assignment_code here instead
2848 # of generate_disposal_code, because values were stored
2849 # in the list using a reference-stealing operation.
2850 for arg in self.args:
2851 arg.generate_post_assignment_code(code)
2854 class ListComprehensionNode(SequenceNode):
2856 subexprs = []
2857 is_sequence_constructor = 0 # not unpackable
2859 child_attrs = ["loop", "append"]
2861 def analyse_types(self, env):
2862 self.type = list_type
2863 self.is_temp = 1
2864 self.append.target = self # this is a CloneNode used in the PyList_Append in the inner loop
2866 def allocate_temps(self, env, result = None):
2867 if debug_temp_alloc:
2868 print("%s Allocating temps" % self)
2869 self.allocate_temp(env, result)
2870 self.loop.analyse_declarations(env)
2871 self.loop.analyse_expressions(env)
2873 def generate_operation_code(self, code):
2874 code.putln("%s = PyList_New(%s); %s" %
2875 (self.result(),
2876 0,
2877 code.error_goto_if_null(self.result(), self.pos)))
2878 self.loop.generate_execution_code(code)
2880 def annotate(self, code):
2881 self.loop.annotate(code)
2884 class ListComprehensionAppendNode(ExprNode):
2886 # Need to be careful to avoid infinite recursion:
2887 # target must not be in child_attrs/subexprs
2888 subexprs = ['expr']
2890 def analyse_types(self, env):
2891 self.expr.analyse_types(env)
2892 if self.expr.type != py_object_type:
2893 self.expr = self.expr.coerce_to_pyobject(env)
2894 self.type = PyrexTypes.c_int_type
2895 self.is_temp = 1
2897 def generate_result_code(self, code):
2898 code.putln("%s = PyList_Append(%s, (PyObject*)%s); %s" %
2899 (self.result(),
2900 self.target.result(),
2901 self.expr.result(),
2902 code.error_goto_if(self.result(), self.pos)))
2905 class DictNode(ExprNode):
2906 # Dictionary constructor.
2908 # key_value_pairs [DictItemNode]
2910 # obj_conversion_errors [PyrexError] used internally
2912 subexprs = ['key_value_pairs']
2914 def compile_time_value(self, denv):
2915 pairs = [(item.key.compile_time_value(denv), item.value.compile_time_value(denv))
2916 for item in self.key_value_pairs]
2917 try:
2918 return dict(pairs)
2919 except Exception, e:
2920 self.compile_time_value_error(e)
2922 def analyse_types(self, env):
2923 hold_errors()
2924 self.type = dict_type
2925 for item in self.key_value_pairs:
2926 item.analyse_types(env)
2927 self.gil_check(env)
2928 self.obj_conversion_errors = held_errors()
2929 release_errors(ignore=True)
2930 self.is_temp = 1
2932 def coerce_to(self, dst_type, env):
2933 if dst_type.is_pyobject:
2934 self.release_errors()
2935 if not self.type.subtype_of(dst_type):
2936 error(self.pos, "Cannot interpret dict as type '%s'" % dst_type)
2937 elif dst_type.is_struct_or_union:
2938 self.type = dst_type
2939 if not dst_type.is_struct and len(self.key_value_pairs) != 1:
2940 error(self.pos, "Exactly one field must be specified to convert to union '%s'" % dst_type)
2941 elif dst_type.is_struct and len(self.key_value_pairs) < len(dst_type.scope.var_entries):
2942 warning(self.pos, "Not all members given for struct '%s'" % dst_type, 1)
2943 for item in self.key_value_pairs:
2944 if isinstance(item.key, CoerceToPyTypeNode):
2945 item.key = item.key.arg
2946 if isinstance(item.key, (StringNode, IdentifierStringNode)):
2947 item.key = NameNode(pos=item.key.pos, name=item.key.value)
2948 if not isinstance(item.key, NameNode):
2949 print item.key
2950 error(item.key.pos, "Struct field must be a name")
2951 else:
2952 member = dst_type.scope.lookup_here(item.key.name)
2953 if not member:
2954 error(item.key.pos, "struct '%s' has no field '%s'" % (dst_type, item.key.name))
2955 else:
2956 value = item.value
2957 if isinstance(value, CoerceToPyTypeNode):
2958 value = value.arg
2959 item.value = value.coerce_to(member.type, env)
2960 else:
2961 self.type = error_type
2962 error(self.pos, "Cannot interpret dict as type '%s'" % dst_type)
2963 return self
2965 def release_errors(self):
2966 for err in self.obj_conversion_errors:
2967 report_error(err)
2968 self.obj_conversion_errors = []
2970 gil_message = "Constructing Python dict"
2972 def allocate_temps(self, env, result = None):
2973 # Custom method used here because key-value
2974 # pairs are evaluated and used one at a time.
2975 self.allocate_temp(env, result)
2976 for item in self.key_value_pairs:
2977 item.key.allocate_temps(env)
2978 item.value.allocate_temps(env)
2979 item.key.release_temp(env)
2980 item.value.release_temp(env)
2982 def generate_evaluation_code(self, code):
2983 # Custom method used here because key-value
2984 # pairs are evaluated and used one at a time.
2985 if self.type.is_pyobject:
2986 self.release_errors()
2987 code.putln(
2988 "%s = PyDict_New(); %s" % (
2989 self.result(),
2990 code.error_goto_if_null(self.result(), self.pos)))
2991 for item in self.key_value_pairs:
2992 item.generate_evaluation_code(code)
2993 if self.type.is_pyobject:
2994 code.put_error_if_neg(self.pos,
2995 "PyDict_SetItem(%s, %s, %s)" % (
2996 self.result(),
2997 item.key.py_result(),
2998 item.value.py_result()))
2999 else:
3000 code.putln("%s.%s = %s;" % (
3001 self.result(),
3002 item.key.name,
3003 item.value.result()))
3004 item.generate_disposal_code(code)
3006 def annotate(self, code):
3007 for item in self.key_value_pairs:
3008 item.annotate(code)
3010 class DictItemNode(ExprNode):
3011 # Represents a single item in a DictNode
3013 # key ExprNode
3014 # value ExprNode
3015 subexprs = ['key', 'value']
3017 def analyse_types(self, env):
3018 self.key.analyse_types(env)
3019 self.value.analyse_types(env)
3020 self.key = self.key.coerce_to_pyobject(env)
3021 self.value = self.value.coerce_to_pyobject(env)
3023 def generate_evaluation_code(self, code):
3024 self.key.generate_evaluation_code(code)
3025 self.value.generate_evaluation_code(code)
3027 def generate_disposal_code(self, code):
3028 self.key.generate_disposal_code(code)
3029 self.value.generate_disposal_code(code)
3031 def __iter__(self):
3032 return iter([self.key, self.value])
3035 class ClassNode(ExprNode):
3036 # Helper class used in the implementation of Python
3037 # class definitions. Constructs a class object given
3038 # a name, tuple of bases and class dictionary.
3040 # name EncodedString Name of the class
3041 # cname string Class name as a Python string
3042 # bases ExprNode Base class tuple
3043 # dict ExprNode Class dict (not owned by this node)
3044 # doc ExprNode or None Doc string
3045 # module_name string Name of defining module
3047 subexprs = ['bases', 'doc']
3049 def analyse_types(self, env):
3050 self.cname = env.intern_identifier(self.name)
3051 self.bases.analyse_types(env)
3052 if self.doc:
3053 self.doc.analyse_types(env)
3054 self.doc = self.doc.coerce_to_pyobject(env)
3055 self.module_name = env.global_scope().qualified_name
3056 self.type = py_object_type
3057 self.gil_check(env)
3058 self.is_temp = 1
3059 env.use_utility_code(create_class_utility_code);
3061 gil_message = "Constructing Python class"
3063 def generate_result_code(self, code):
3064 if self.doc:
3065 code.put_error_if_neg(self.pos,
3066 'PyDict_SetItemString(%s, "__doc__", %s)' % (
3067 self.dict.py_result(),
3068 self.doc.py_result()))
3069 code.putln(
3070 '%s = __Pyx_CreateClass(%s, %s, %s, "%s"); %s' % (
3071 self.result(),
3072 self.bases.py_result(),
3073 self.dict.py_result(),
3074 self.cname,
3075 self.module_name,
3076 code.error_goto_if_null(self.result(), self.pos)))
3079 class UnboundMethodNode(ExprNode):
3080 # Helper class used in the implementation of Python
3081 # class definitions. Constructs an unbound method
3082 # object from a class and a function.
3084 # class_cname string C var holding the class object
3085 # function ExprNode Function object
3087 subexprs = ['function']
3089 def analyse_types(self, env):
3090 self.function.analyse_types(env)
3091 self.type = py_object_type
3092 self.gil_check(env)
3093 self.is_temp = 1
3095 gil_message = "Constructing an unbound method"
3097 def generate_result_code(self, code):
3098 code.putln(
3099 "%s = PyMethod_New(%s, 0, %s); %s" % (
3100 self.result(),
3101 self.function.py_result(),
3102 self.class_cname,
3103 code.error_goto_if_null(self.result(), self.pos)))
3106 class PyCFunctionNode(AtomicExprNode):
3107 # Helper class used in the implementation of Python
3108 # class definitions. Constructs a PyCFunction object
3109 # from a PyMethodDef struct.
3111 # pymethdef_cname string PyMethodDef structure
3113 def analyse_types(self, env):
3114 self.type = py_object_type
3115 self.gil_check(env)
3116 self.is_temp = 1
3118 gil_message = "Constructing Python function"
3120 def generate_result_code(self, code):
3121 code.putln(
3122 "%s = PyCFunction_New(&%s, 0); %s" % (
3123 self.result(),
3124 self.pymethdef_cname,
3125 code.error_goto_if_null(self.result(), self.pos)))
3127 #-------------------------------------------------------------------
3129 # Unary operator nodes
3131 #-------------------------------------------------------------------
3133 compile_time_unary_operators = {
3134 'not': operator.not_,
3135 '~': operator.inv,
3136 '-': operator.neg,
3137 '+': operator.pos,
3140 class UnopNode(ExprNode):
3141 # operator string
3142 # operand ExprNode
3144 # Processing during analyse_expressions phase:
3146 # analyse_c_operation
3147 # Called when the operand is not a pyobject.
3148 # - Check operand type and coerce if needed.
3149 # - Determine result type and result code fragment.
3150 # - Allocate temporary for result if needed.
3152 subexprs = ['operand']
3154 def compile_time_value(self, denv):
3155 func = compile_time_unary_operators.get(self.operator)
3156 if not func:
3157 error(self.pos,
3158 "Unary '%s' not supported in compile-time expression"
3159 % self.operator)
3160 operand = self.operand.compile_time_value(denv)
3161 try:
3162 return func(operand)
3163 except Exception, e:
3164 self.compile_time_value_error(e)
3166 def analyse_types(self, env):
3167 self.operand.analyse_types(env)
3168 if self.is_py_operation():
3169 self.coerce_operand_to_pyobject(env)
3170 self.type = py_object_type
3171 self.gil_check(env)
3172 self.is_temp = 1
3173 else:
3174 self.analyse_c_operation(env)
3176 def check_const(self):
3177 self.operand.check_const()
3179 def is_py_operation(self):
3180 return self.operand.type.is_pyobject
3182 def coerce_operand_to_pyobject(self, env):
3183 self.operand = self.operand.coerce_to_pyobject(env)
3185 def generate_result_code(self, code):
3186 if self.operand.type.is_pyobject:
3187 self.generate_py_operation_code(code)
3188 else:
3189 if self.is_temp:
3190 self.generate_c_operation_code(code)
3192 def generate_py_operation_code(self, code):
3193 function = self.py_operation_function()
3194 code.putln(
3195 "%s = %s(%s); %s" % (
3196 self.result(),
3197 function,
3198 self.operand.py_result(),
3199 code.error_goto_if_null(self.result(), self.pos)))
3201 def type_error(self):
3202 if not self.operand.type.is_error:
3203 error(self.pos, "Invalid operand type for '%s' (%s)" %
3204 (self.operator, self.operand.type))
3205 self.type = PyrexTypes.error_type
3208 class NotNode(ExprNode):
3209 # 'not' operator
3211 # operand ExprNode
3213 def compile_time_value(self, denv):
3214 operand = self.operand.compile_time_value(denv)
3215 try:
3216 return not operand
3217 except Exception, e:
3218 self.compile_time_value_error(e)
3220 subexprs = ['operand']
3222 def analyse_types(self, env):
3223 self.operand.analyse_types(env)
3224 self.operand = self.operand.coerce_to_boolean(env)
3225 self.type = PyrexTypes.c_bint_type
3227 def calculate_result_code(self):
3228 return "(!%s)" % self.operand.result()
3230 def generate_result_code(self, code):
3231 pass
3234 class UnaryPlusNode(UnopNode):
3235 # unary '+' operator
3237 operator = '+'
3239 def analyse_c_operation(self, env):
3240 self.type = self.operand.type
3242 def py_operation_function(self):
3243 return "PyNumber_Positive"
3245 def calculate_result_code(self):
3246 return self.operand.result()
3249 class UnaryMinusNode(UnopNode):
3250 # unary '-' operator
3252 operator = '-'
3254 def analyse_c_operation(self, env):
3255 if self.operand.type.is_numeric:
3256 self.type = self.operand.type
3257 else:
3258 self.type_error()
3260 def py_operation_function(self):
3261 return "PyNumber_Negative"
3263 def calculate_result_code(self):
3264 return "(-%s)" % self.operand.result()
3267 class TildeNode(UnopNode):
3268 # unary '~' operator
3270 def analyse_c_operation(self, env):
3271 if self.operand.type.is_int:
3272 self.type = self.operand.type
3273 else:
3274 self.type_error()
3276 def py_operation_function(self):
3277 return "PyNumber_Invert"
3279 def calculate_result_code(self):
3280 return "(~%s)" % self.operand.result()
3283 class AmpersandNode(ExprNode):
3284 # The C address-of operator.
3286 # operand ExprNode
3288 subexprs = ['operand']
3290 def analyse_types(self, env):
3291 self.operand.analyse_types(env)
3292 argtype = self.operand.type
3293 if not (argtype.is_cfunction or self.operand.is_lvalue()):
3294 self.error("Taking address of non-lvalue")
3295 return
3296 if argtype.is_pyobject:
3297 self.error("Cannot take address of Python variable")
3298 return
3299 self.type = PyrexTypes.c_ptr_type(argtype)
3301 def check_const(self):
3302 self.operand.check_const_addr()
3304 def error(self, mess):
3305 error(self.pos, mess)
3306 self.type = PyrexTypes.error_type
3307 self.result_code = "<error>"
3309 def calculate_result_code(self):
3310 return "(&%s)" % self.operand.result()
3312 def generate_result_code(self, code):
3313 pass
3316 unop_node_classes = {
3317 "+": UnaryPlusNode,
3318 "-": UnaryMinusNode,
3319 "~": TildeNode,
3322 def unop_node(pos, operator, operand):
3323 # Construct unnop node of appropriate class for
3324 # given operator.
3325 if isinstance(operand, IntNode) and operator == '-':
3326 return IntNode(pos = operand.pos, value = str(-int(operand.value, 0)))
3327 elif isinstance(operand, UnopNode) and operand.operator == operator:
3328 warning(pos, "Python has no increment/decrement operator: %s%sx = %s(%sx) = x" % ((operator,)*4), 5)
3329 return unop_node_classes[operator](pos,
3330 operator = operator,
3331 operand = operand)
3334 class TypecastNode(ExprNode):
3335 # C type cast
3337 # operand ExprNode
3338 # base_type CBaseTypeNode
3339 # declarator CDeclaratorNode
3341 # If used from a transform, one can if wanted specify the attribute
3342 # "type" directly and leave base_type and declarator to None
3344 subexprs = ['operand']
3345 base_type = declarator = type = None
3347 def analyse_types(self, env):
3348 if self.type is None:
3349 base_type = self.base_type.analyse(env)
3350 _, self.type = self.declarator.analyse(base_type, env)
3351 if self.type.is_cfunction:
3352 error(self.pos,
3353 "Cannot cast to a function type")
3354 self.type = PyrexTypes.error_type
3355 self.operand.analyse_types(env)
3356 to_py = self.type.is_pyobject
3357 from_py = self.operand.type.is_pyobject
3358 if from_py and not to_py and self.operand.is_ephemeral() and not self.type.is_numeric:
3359 error(self.pos, "Casting temporary Python object to non-numeric non-Python type")
3360 if to_py and not from_py:
3361 if (self.operand.type.to_py_function and
3362 self.operand.type.create_convert_utility_code(env)):
3363 self.result_ctype = py_object_type
3364 self.operand = self.operand.coerce_to_pyobject(env)
3365 else:
3366 warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.operand.type, self.type))
3367 self.operand = self.operand.coerce_to_simple(env)
3368 elif from_py and not to_py:
3369 if self.type.from_py_function:
3370 self.operand = self.operand.coerce_to(self.type, env)
3371 else:
3372 warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.type, self.operand.type))
3373 elif from_py and to_py:
3374 if self.typecheck and self.type.is_extension_type:
3375 self.operand = PyTypeTestNode(self.operand, self.type, env)
3377 def check_const(self):
3378 self.operand.check_const()
3380 def calculate_result_code(self):
3381 opnd = self.operand
3382 return self.type.cast_code(opnd.result())
3384 def result_as(self, type):
3385 if self.type.is_pyobject and not self.is_temp:
3386 # Optimise away some unnecessary casting
3387 return self.operand.result_as(type)
3388 else:
3389 return ExprNode.result_as(self, type)
3391 def generate_result_code(self, code):
3392 if self.is_temp:
3393 code.putln(
3394 "%s = (PyObject *)%s;" % (
3395 self.result(),
3396 self.operand.result()))
3397 code.put_incref(self.result(), self.ctype())
3400 class SizeofNode(ExprNode):
3401 # Abstract base class for sizeof(x) expression nodes.
3403 type = PyrexTypes.c_int_type
3405 def check_const(self):
3406 pass
3408 def generate_result_code(self, code):
3409 pass
3412 class SizeofTypeNode(SizeofNode):
3413 # C sizeof function applied to a type
3415 # base_type CBaseTypeNode
3416 # declarator CDeclaratorNode
3418 subexprs = []
3419 arg_type = None
3421 def analyse_types(self, env):
3422 # we may have incorrectly interpreted a dotted name as a type rather than an attribute
3423 # this could be better handled by more uniformly treating types as runtime-available objects
3424 if 0 and self.base_type.module_path:
3425 path = self.base_type.module_path
3426 obj = env.lookup(path[0])
3427 if obj.as_module is None:
3428 operand = NameNode(pos=self.pos, name=path[0])
3429 for attr in path[1:]:
3430 operand = AttributeNode(pos=self.pos, obj=operand, attribute=attr)
3431 operand = AttributeNode(pos=self.pos, obj=operand, attribute=self.base_type.name)
3432 self.operand = operand
3433 self.__class__ = SizeofVarNode
3434 self.analyse_types(env)
3435 return
3436 if self.arg_type is None:
3437 base_type = self.base_type.analyse(env)
3438 _, arg_type = self.declarator.analyse(base_type, env)
3439 self.arg_type = arg_type
3440 self.check_type()
3442 def check_type(self):
3443 arg_type = self.arg_type
3444 if arg_type.is_pyobject and not arg_type.is_extension_type:
3445 error(self.pos, "Cannot take sizeof Python object")
3446 elif arg_type.is_void:
3447 error(self.pos, "Cannot take sizeof void")
3448 elif not arg_type.is_complete():
3449 error(self.pos, "Cannot take sizeof incomplete type '%s'" % arg_type)
3451 def calculate_result_code(self):
3452 if self.arg_type.is_extension_type:
3453 # the size of the pointer is boring
3454 # we want the size of the actual struct
3455 arg_code = self.arg_type.declaration_code("", deref=1)
3456 else:
3457 arg_code = self.arg_type.declaration_code("")
3458 return "(sizeof(%s))" % arg_code
3461 class SizeofVarNode(SizeofNode):
3462 # C sizeof function applied to a variable
3464 # operand ExprNode
3466 subexprs = ['operand']
3468 def analyse_types(self, env):
3469 # We may actually be looking at a type rather than a variable...
3470 # If we are, traditional analysis would fail...
3471 operand_as_type = self.operand.analyse_as_type(env)
3472 if operand_as_type:
3473 self.arg_type = operand_as_type
3474 self.__class__ = SizeofTypeNode
3475 self.check_type()
3476 else:
3477 self.operand.analyse_types(env)
3479 def calculate_result_code(self):
3480 return "(sizeof(%s))" % self.operand.result()
3482 def generate_result_code(self, code):
3483 pass
3486 #-------------------------------------------------------------------
3488 # Binary operator nodes
3490 #-------------------------------------------------------------------
3492 def _not_in(x, seq):
3493 return x not in seq
3495 compile_time_binary_operators = {
3496 '<': operator.lt,
3497 '<=': operator.le,
3498 '==': operator.eq,
3499 '!=': operator.ne,
3500 '>=': operator.ge,
3501 '>': operator.gt,
3502 'is': operator.is_,
3503 'is_not': operator.is_not,
3504 '+': operator.add,
3505 '&': operator.and_,
3506 '/': operator.div,
3507 '//': operator.floordiv,
3508 '<<': operator.lshift,
3509 '%': operator.mod,
3510 '*': operator.mul,
3511 '|': operator.or_,
3512 '**': operator.pow,
3513 '>>': operator.rshift,
3514 '-': operator.sub,
3515 #'/': operator.truediv,
3516 '^': operator.xor,
3517 'in': operator.contains,
3518 'not_in': _not_in,
3521 def get_compile_time_binop(node):
3522 func = compile_time_binary_operators.get(node.operator)
3523 if not func:
3524 error(node.pos,
3525 "Binary '%s' not supported in compile-time expression"
3526 % node.operator)
3527 return func
3529 class BinopNode(NewTempExprNode):
3530 # operator string
3531 # operand1 ExprNode
3532 # operand2 ExprNode
3534 # Processing during analyse_expressions phase:
3536 # analyse_c_operation
3537 # Called when neither operand is a pyobject.
3538 # - Check operand types and coerce if needed.
3539 # - Determine result type and result code fragment.
3540 # - Allocate temporary for result if needed.
3542 subexprs = ['operand1', 'operand2']
3544 def compile_time_value(self, denv):
3545 func = get_compile_time_binop(self)
3546 operand1 = self.operand1.compile_time_value(denv)
3547 operand2 = self.operand2.compile_time_value(denv)
3548 try:
3549 return func(operand1, operand2)
3550 except Exception, e:
3551 self.compile_time_value_error(e)
3553 def analyse_types(self, env):
3554 self.operand1.analyse_types(env)
3555 self.operand2.analyse_types(env)
3556 if self.is_py_operation():
3557 self.coerce_operands_to_pyobjects(env)
3558 self.type = py_object_type
3559 self.gil_check(env)
3560 self.is_temp = 1
3561 if Options.incref_local_binop and self.operand1.type.is_pyobject:
3562 self.operand1 = self.operand1.coerce_to_temp(env)
3563 else:
3564 self.analyse_c_operation(env)
3566 def is_py_operation(self):
3567 return (self.operand1.type.is_pyobject
3568 or self.operand2.type.is_pyobject)
3570 def coerce_operands_to_pyobjects(self, env):
3571 self.operand1 = self.operand1.coerce_to_pyobject(env)
3572 self.operand2 = self.operand2.coerce_to_pyobject(env)
3574 def check_const(self):
3575 self.operand1.check_const()
3576 self.operand2.check_const()
3578 def generate_result_code(self, code):
3579 #print "BinopNode.generate_result_code:", self.operand1, self.operand2 ###
3580 if self.operand1.type.is_pyobject:
3581 function = self.py_operation_function()
3582 if function == "PyNumber_Power":
3583 extra_args = ", Py_None"
3584 else:
3585 extra_args = ""
3586 code.putln(
3587 "%s = %s(%s, %s%s); %s" % (
3588 self.result(),
3589 function,
3590 self.operand1.py_result(),
3591 self.operand2.py_result(),
3592 extra_args,
3593 code.error_goto_if_null(self.result(), self.pos)))
3594 else:
3595 if self.is_temp:
3596 self.generate_c_operation_code(code)
3598 def type_error(self):
3599 if not (self.operand1.type.is_error
3600 or self.operand2.type.is_error):
3601 error(self.pos, "Invalid operand types for '%s' (%s; %s)" %
3602 (self.operator, self.operand1.type,
3603 self.operand2.type))
3604 self.type = PyrexTypes.error_type
3607 class NumBinopNode(BinopNode):
3608 # Binary operation taking numeric arguments.
3610 def analyse_c_operation(self, env):
3611 type1 = self.operand1.type
3612 type2 = self.operand2.type
3613 if self.operator == "**" and type1.is_int and type2.is_int:
3614 error(self.pos, "** with two C int types is ambiguous")
3615 self.type = error_type
3616 return
3617 self.type = self.compute_c_result_type(type1, type2)
3618 if not self.type:
3619 self.type_error()
3621 def compute_c_result_type(self, type1, type2):
3622 if self.c_types_okay(type1, type2):
3623 return PyrexTypes.widest_numeric_type(type1, type2)
3624 else:
3625 return None
3627 def c_types_okay(self, type1, type2):
3628 #print "NumBinopNode.c_types_okay:", type1, type2 ###
3629 return (type1.is_numeric or type1.is_enum) \
3630 and (type2.is_numeric or type2.is_enum)
3632 def calculate_result_code(self):
3633 return "(%s %s %s)" % (
3634 self.operand1.result(),
3635 self.operator,
3636 self.operand2.result())
3638 def py_operation_function(self):
3639 return self.py_functions[self.operator]
3641 py_functions = {
3642 "|": "PyNumber_Or",
3643 "^": "PyNumber_Xor",
3644 "&": "PyNumber_And",
3645 "<<": "PyNumber_Lshift",
3646 ">>": "PyNumber_Rshift",
3647 "+": "PyNumber_Add",
3648 "-": "PyNumber_Subtract",
3649 "*": "PyNumber_Multiply",
3650 "/": "__Pyx_PyNumber_Divide",
3651 "//": "PyNumber_FloorDivide",
3652 "%": "PyNumber_Remainder",
3653 "**": "PyNumber_Power"
3657 class IntBinopNode(NumBinopNode):
3658 # Binary operation taking integer arguments.
3660 def c_types_okay(self, type1, type2):
3661 #print "IntBinopNode.c_types_okay:", type1, type2 ###
3662 return (type1.is_int or type1.is_enum) \
3663 and (type2.is_int or type2.is_enum)
3666 class AddNode(NumBinopNode):
3667 # '+' operator.
3669 def is_py_operation(self):
3670 if self.operand1.type.is_string \
3671 and self.operand2.type.is_string:
3672 return 1
3673 else:
3674 return NumBinopNode.is_py_operation(self)
3676 def compute_c_result_type(self, type1, type2):
3677 #print "AddNode.compute_c_result_type:", type1, self.operator, type2 ###
3678 if (type1.is_ptr or type1.is_array) and (type2.is_int or type2.is_enum):
3679 return type1
3680 elif (type2.is_ptr or type2.is_array) and (type1.is_int or type1.is_enum):
3681 return type2
3682 else:
3683 return NumBinopNode.compute_c_result_type(
3684 self, type1, type2)
3687 class SubNode(NumBinopNode):
3688 # '-' operator.
3690 def compute_c_result_type(self, type1, type2):
3691 if (type1.is_ptr or type1.is_array) and (type2.is_int or type2.is_enum):
3692 return type1
3693 elif (type1.is_ptr or type1.is_array) and (type2.is_ptr or type2.is_array):
3694 return PyrexTypes.c_int_type
3695 else:
3696 return NumBinopNode.compute_c_result_type(
3697 self, type1, type2)
3700 class MulNode(NumBinopNode):
3701 # '*' operator.
3703 def is_py_operation(self):
3704 type1 = self.operand1.type
3705 type2 = self.operand2.type
3706 if (type1.is_string and type2.is_int) \
3707 or (type2.is_string and type1.is_int):
3708 return 1
3709 else:
3710 return NumBinopNode.is_py_operation(self)
3713 class FloorDivNode(NumBinopNode):
3714 # '//' operator.
3716 def calculate_result_code(self):
3717 return "(%s %s %s)" % (
3718 self.operand1.result(),
3719 "/", # c division is by default floor-div
3720 self.operand2.result())
3723 class ModNode(NumBinopNode):
3724 # '%' operator.
3726 def is_py_operation(self):
3727 return (self.operand1.type.is_string
3728 or self.operand2.type.is_string
3729 or NumBinopNode.is_py_operation(self))
3731 def calculate_result_code(self):
3732 if self.operand1.type.is_float or self.operand2.type.is_float:
3733 return "fmod(%s, %s)" % (
3734 self.operand1.result(),
3735 self.operand2.result())
3736 else:
3737 return "(%s %% %s)" % (
3738 self.operand1.result(),
3739 self.operand2.result())
3741 class PowNode(NumBinopNode):
3742 # '**' operator.
3744 def compute_c_result_type(self, type1, type2):
3745 if self.c_types_okay(type1, type2):
3746 return PyrexTypes.c_double_type
3747 else:
3748 return None
3750 def c_types_okay(self, type1, type2):
3751 return (type1.is_float or type2.is_float) and \
3752 NumBinopNode.c_types_okay(self, type1, type2)
3754 def type_error(self):
3755 if not (self.operand1.type.is_error or self.operand2.type.is_error):
3756 if self.operand1.type.is_int and self.operand2.type.is_int:
3757 error(self.pos, "C has no integer powering, use python ints or floats instead '%s' (%s; %s)" %
3758 (self.operator, self.operand1.type, self.operand2.type))
3759 else:
3760 NumBinopNode.type_error(self)
3761 self.type = PyrexTypes.error_type
3763 def calculate_result_code(self):
3764 return "pow(%s, %s)" % (
3765 self.operand1.result(), self.operand2.result())
3768 class BoolBinopNode(ExprNode):
3769 # Short-circuiting boolean operation.
3771 # operator string
3772 # operand1 ExprNode
3773 # operand2 ExprNode
3774 # temp_bool ExprNode used internally
3776 temp_bool = None
3778 subexprs = ['operand1', 'operand2', 'temp_bool']
3780 def compile_time_value(self, denv):
3781 if self.operator == 'and':
3782 return self.operand1.compile_time_value(denv) \
3783 and self.operand2.compile_time_value(denv)
3784 else:
3785 return self.operand1.compile_time_value(denv) \
3786 or self.operand2.compile_time_value(denv)
3788 def coerce_to_boolean(self, env):
3789 self.operand1 = self.operand1.coerce_to_boolean(env)
3790 self.operand2 = self.operand2.coerce_to_boolean(env)
3791 self.type = PyrexTypes.c_bint_type
3792 return self
3794 def analyse_types(self, env):
3795 self.operand1.analyse_types(env)
3796 self.operand2.analyse_types(env)
3797 if self.operand1.type.is_pyobject or \
3798 self.operand2.type.is_pyobject:
3799 self.operand1 = self.operand1.coerce_to_pyobject(env)
3800 self.operand2 = self.operand2.coerce_to_pyobject(env)
3801 self.temp_bool = TempNode(self.pos, PyrexTypes.c_bint_type, env)
3802 self.type = py_object_type
3803 self.gil_check(env)
3804 else:
3805 self.operand1 = self.operand1.coerce_to_boolean(env)
3806 self.operand2 = self.operand2.coerce_to_boolean(env)
3807 self.type = PyrexTypes.c_bint_type
3808 # For what we're about to do, it's vital that
3809 # both operands be temp nodes.
3810 self.operand1 = self.operand1.coerce_to_temp(env) #CTT
3811 self.operand2 = self.operand2.coerce_to_temp(env)
3812 self.is_temp = 1
3814 gil_message = "Truth-testing Python object"
3816 def allocate_temps(self, env, result_code = None):
3817 # We don't need both operands at the same time, and
3818 # one of the operands will also be our result. So we
3819 # use an allocation strategy here which results in
3820 # this node and both its operands sharing the same
3821 # result variable. This allows us to avoid some
3822 # assignments and increfs/decrefs that would otherwise
3823 # be necessary.
3824 self.allocate_temp(env, result_code)
3825 self.operand1.allocate_temps(env, self.result())
3826 if self.temp_bool:
3827 self.temp_bool.allocate_temp(env)
3828 self.temp_bool.release_temp(env)
3829 self.operand2.allocate_temps(env, self.result())
3830 # We haven't called release_temp on either operand,
3831 # because although they are temp nodes, they don't own
3832 # their result variable. And because they are temp
3833 # nodes, any temps in their subnodes will have been
3834 # released before their allocate_temps returned.
3835 # Therefore, they contain no temp vars that need to
3836 # be released.
3838 def check_const(self):
3839 self.operand1.check_const()
3840 self.operand2.check_const()
3842 def calculate_result_code(self):
3843 return "(%s %s %s)" % (
3844 self.operand1.result(),
3845 self.py_to_c_op[self.operator],
3846 self.operand2.result())
3848 py_to_c_op = {'and': "&&", 'or': "||"}
3850 def generate_evaluation_code(self, code):
3851 self.operand1.generate_evaluation_code(code)
3852 test_result = self.generate_operand1_test(code)
3853 if self.operator == 'and':
3854 sense = ""
3855 else:
3856 sense = "!"
3857 code.putln(
3858 "if (%s%s) {" % (
3859 sense,
3860 test_result))
3861 self.operand1.generate_disposal_code(code)
3862 self.operand2.generate_evaluation_code(code)
3863 code.putln(
3864 "}")
3866 def generate_operand1_test(self, code):
3867 # Generate code to test the truth of the first operand.
3868 if self.type.is_pyobject:
3869 test_result = self.temp_bool.result()
3870 code.putln(
3871 "%s = __Pyx_PyObject_IsTrue(%s); %s" % (
3872 test_result,
3873 self.operand1.py_result(),
3874 code.error_goto_if_neg(test_result, self.pos)))
3875 else:
3876 test_result = self.operand1.result()
3877 return test_result
3880 class CondExprNode(ExprNode):
3881 # Short-circuiting conditional expression.
3883 # test ExprNode
3884 # true_val ExprNode
3885 # false_val ExprNode
3887 temp_bool = None
3888 true_val = None
3889 false_val = None
3891 subexprs = ['test', 'true_val', 'false_val']
3893 def analyse_types(self, env):
3894 self.test.analyse_types(env)
3895 self.test = self.test.coerce_to_boolean(env)
3896 self.true_val.analyse_types(env)
3897 self.false_val.analyse_types(env)
3898 self.type = self.compute_result_type(self.true_val.type, self.false_val.type)
3899 if self.true_val.type.is_pyobject or self.false_val.type.is_pyobject:
3900 self.true_val = self.true_val.coerce_to(self.type, env)
3901 self.false_val = self.false_val.coerce_to(self.type, env)
3902 # must be tmp variables so they can share a result
3903 self.true_val = self.true_val.coerce_to_temp(env)
3904 self.false_val = self.false_val.coerce_to_temp(env)
3905 self.is_temp = 1
3906 if self.type == PyrexTypes.error_type:
3907 self.type_error()
3909 def allocate_temps(self, env, result_code = None):
3910 # We only ever evaluate one side, and this is
3911 # after evaluating the truth value, so we may
3912 # use an allocation strategy here which results in
3913 # this node and both its operands sharing the same
3914 # result variable. This allows us to avoid some
3915 # assignments and increfs/decrefs that would otherwise
3916 # be necessary.
3917 self.allocate_temp(env, result_code)
3918 self.test.allocate_temps(env, result_code)
3919 self.true_val.allocate_temps(env, self.result())
3920 self.false_val.allocate_temps(env, self.result())
3921 # We haven't called release_temp on either value,
3922 # because although they are temp nodes, they don't own
3923 # their result variable. And because they are temp
3924 # nodes, any temps in their subnodes will have been
3925 # released before their allocate_temps returned.
3926 # Therefore, they contain no temp vars that need to
3927 # be released.
3929 def compute_result_type(self, type1, type2):
3930 if type1 == type2:
3931 return type1
3932 elif type1.is_numeric and type2.is_numeric:
3933 return PyrexTypes.widest_numeric_type(type1, type2)
3934 elif type1.is_extension_type and type1.subtype_of_resolved_type(type2):
3935 return type2
3936 elif type2.is_extension_type and type2.subtype_of_resolved_type(type1):
3937 return type1
3938 elif type1.is_pyobject or type2.is_pyobject:
3939 return py_object_type
3940 elif type1.assignable_from(type2):
3941 return type1
3942 elif type2.assignable_from(type1):
3943 return type2
3944 else:
3945 return PyrexTypes.error_type
3947 def type_error(self):
3948 if not (self.true_val.type.is_error or self.false_val.type.is_error):
3949 error(self.pos, "Incompatable types in conditional expression (%s; %s)" %
3950 (self.true_val.type, self.false_val.type))
3951 self.type = PyrexTypes.error_type
3953 def check_const(self):
3954 self.test.check_const()
3955 self.true_val.check_const()
3956 self.false_val.check_const()
3958 def generate_evaluation_code(self, code):
3959 self.test.generate_evaluation_code(code)
3960 code.putln("if (%s) {" % self.test.result() )
3961 self.true_val.generate_evaluation_code(code)
3962 code.putln("} else {")
3963 self.false_val.generate_evaluation_code(code)
3964 code.putln("}")
3965 self.test.generate_disposal_code(code)
3967 richcmp_constants = {
3968 "<" : "Py_LT",
3969 "<=": "Py_LE",
3970 "==": "Py_EQ",
3971 "!=": "Py_NE",
3972 "<>": "Py_NE",
3973 ">" : "Py_GT",
3974 ">=": "Py_GE",
3977 class CmpNode:
3978 # Mixin class containing code common to PrimaryCmpNodes
3979 # and CascadedCmpNodes.
3981 def cascaded_compile_time_value(self, operand1, denv):
3982 func = get_compile_time_binop(self)
3983 operand2 = self.operand2.compile_time_value(denv)
3984 try:
3985 result = func(operand1, operand2)
3986 except Exception, e:
3987 self.compile_time_value_error(e)
3988 result = None
3989 if result:
3990 cascade = self.cascade
3991 if cascade:
3992 result = result and cascade.compile_time_value(operand2, denv)
3993 return result
3995 def is_python_comparison(self):
3996 return (self.has_python_operands()
3997 or (self.cascade and self.cascade.is_python_comparison())
3998 or self.operator in ('in', 'not_in'))
4000 def is_python_result(self):
4001 return ((self.has_python_operands() and self.operator not in ('is', 'is_not', 'in', 'not_in'))
4002 or (self.cascade and self.cascade.is_python_result()))
4004 def check_types(self, env, operand1, op, operand2):
4005 if not self.types_okay(operand1, op, operand2):
4006 error(self.pos, "Invalid types for '%s' (%s, %s)" %
4007 (self.operator, operand1.type, operand2.type))
4009 def types_okay(self, operand1, op, operand2):
4010 type1 = operand1.type
4011 type2 = operand2.type
4012 if type1.is_error or type2.is_error:
4013 return 1
4014 if type1.is_pyobject: # type2 will be, too
4015 return 1
4016 elif type1.is_ptr or type1.is_array:
4017 return type1.is_null_ptr or type2.is_null_ptr \
4018 or ((type2.is_ptr or type2.is_array)
4019 and type1.base_type.same_as(type2.base_type))
4020 elif ((type1.is_numeric and type2.is_numeric
4021 or type1.is_enum and (type1 is type2 or type2.is_int)
4022 or type1.is_int and type2.is_enum)
4023 and op not in ('is', 'is_not')):
4024 return 1
4025 else:
4026 return type1.is_cfunction and type1.is_cfunction and type1 == type2
4028 def generate_operation_code(self, code, result_code,
4029 operand1, op , operand2):
4030 if self.type is PyrexTypes.py_object_type:
4031 coerce_result = "__Pyx_PyBool_FromLong"
4032 else:
4033 coerce_result = ""
4034 if 'not' in op: negation = "!"
4035 else: negation = ""
4036 if op == 'in' or op == 'not_in':
4037 code.putln(
4038 "%s = %s(%sPySequence_Contains(%s, %s)); %s" % (
4039 result_code,
4040 coerce_result,
4041 negation,
4042 operand2.py_result(),
4043 operand1.py_result(),
4044 code.error_goto_if_neg(result_code, self.pos)))
4045 elif (operand1.type.is_pyobject
4046 and op not in ('is', 'is_not')):
4047 code.putln("%s = PyObject_RichCompare(%s, %s, %s); %s" % (
4048 result_code,
4049 operand1.py_result(),
4050 operand2.py_result(),
4051 richcmp_constants[op],
4052 code.error_goto_if_null(result_code, self.pos)))
4053 else:
4054 type1 = operand1.type
4055 type2 = operand2.type
4056 if (type1.is_extension_type or type2.is_extension_type) \
4057 and not type1.same_as(type2):
4058 common_type = py_object_type
4059 elif type1.is_numeric:
4060 common_type = PyrexTypes.widest_numeric_type(type1, type2)
4061 else:
4062 common_type = type1
4063 code1 = operand1.result_as(common_type)
4064 code2 = operand2.result_as(common_type)
4065 code.putln("%s = %s(%s %s %s);" % (
4066 result_code,
4067 coerce_result,
4068 code1,
4069 self.c_operator(op),
4070 code2))
4072 def c_operator(self, op):
4073 if op == 'is':
4074 return "=="
4075 elif op == 'is_not':
4076 return "!="
4077 else:
4078 return op
4081 class PrimaryCmpNode(ExprNode, CmpNode):
4082 # Non-cascaded comparison or first comparison of
4083 # a cascaded sequence.
4085 # operator string
4086 # operand1 ExprNode
4087 # operand2 ExprNode
4088 # cascade CascadedCmpNode
4090 # We don't use the subexprs mechanism, because
4091 # things here are too complicated for it to handle.
4092 # Instead, we override all the framework methods
4093 # which use it.
4095 child_attrs = ['operand1', 'operand2', 'cascade']
4097 cascade = None
4099 def compile_time_value(self, denv):
4100 operand1 = self.operand1.compile_time_value(denv)
4101 return self.cascaded_compile_time_value(operand1, denv)
4103 def analyse_types(self, env):
4104 self.operand1.analyse_types(env)
4105 self.operand2.analyse_types(env)
4106 if self.cascade:
4107 self.cascade.analyse_types(env, self.operand2)
4108 self.is_pycmp = self.is_python_comparison()
4109 if self.is_pycmp:
4110 self.coerce_operands_to_pyobjects(env)
4111 if self.has_int_operands():
4112 self.coerce_chars_to_ints(env)
4113 if self.cascade:
4114 self.operand2 = self.operand2.coerce_to_simple(env)
4115 self.cascade.coerce_cascaded_operands_to_temp(env)
4116 self.check_operand_types(env)
4117 if self.is_python_result():
4118 self.type = PyrexTypes.py_object_type
4119 else:
4120 self.type = PyrexTypes.c_bint_type
4121 cdr = self.cascade
4122 while cdr:
4123 cdr.type = self.type
4124 cdr = cdr.cascade
4125 if self.is_pycmp or self.cascade:
4126 self.is_temp = 1
4128 def check_operand_types(self, env):
4129 self.check_types(env,
4130 self.operand1, self.operator, self.operand2)
4131 if self.cascade:
4132 self.cascade.check_operand_types(env, self.operand2)
4134 def has_python_operands(self):
4135 return (self.operand1.type.is_pyobject
4136 or self.operand2.type.is_pyobject)
4138 def coerce_operands_to_pyobjects(self, env):
4139 self.operand1 = self.operand1.coerce_to_pyobject(env)
4140 self.operand2 = self.operand2.coerce_to_pyobject(env)
4141 if self.cascade:
4142 self.cascade.coerce_operands_to_pyobjects(env)
4144 def has_int_operands(self):
4145 return (self.operand1.type.is_int or self.operand2.type.is_int) \
4146 or (self.cascade and self.cascade.has_int_operands())
4148 def coerce_chars_to_ints(self, env):
4149 # coerce literal single-char strings to c chars
4150 if self.operand1.type.is_string and isinstance(self.operand1, StringNode):
4151 self.operand1 = self.operand1.coerce_to(PyrexTypes.c_uchar_type, env)
4152 if self.operand2.type.is_string and isinstance(self.operand2, StringNode):
4153 self.operand2 = self.operand2.coerce_to(PyrexTypes.c_uchar_type, env)
4154 if self.cascade:
4155 self.cascade.coerce_chars_to_ints(env)
4157 def allocate_subexpr_temps(self, env):
4158 self.operand1.allocate_temps(env)
4159 self.operand2.allocate_temps(env)
4160 if self.cascade:
4161 self.cascade.allocate_subexpr_temps(env)
4163 def release_subexpr_temps(self, env):
4164 self.operand1.release_temp(env)
4165 self.operand2.release_temp(env)
4166 if self.cascade:
4167 self.cascade.release_subexpr_temps(env)
4169 def check_const(self):
4170 self.operand1.check_const()
4171 self.operand2.check_const()
4172 if self.cascade:
4173 self.not_const()
4175 def calculate_result_code(self):
4176 return "(%s %s %s)" % (
4177 self.operand1.result(),
4178 self.c_operator(self.operator),
4179 self.operand2.result())
4181 def generate_evaluation_code(self, code):
4182 self.operand1.generate_evaluation_code(code)
4183 self.operand2.generate_evaluation_code(code)
4184 if self.is_temp:
4185 self.generate_operation_code(code, self.result(),
4186 self.operand1, self.operator, self.operand2)
4187 if self.cascade:
4188 self.cascade.generate_evaluation_code(code,
4189 self.result(), self.operand2)
4190 self.operand1.generate_disposal_code(code)
4191 self.operand2.generate_disposal_code(code)
4193 def generate_subexpr_disposal_code(self, code):
4194 # If this is called, it is a non-cascaded cmp,
4195 # so only need to dispose of the two main operands.
4196 self.operand1.generate_disposal_code(code)
4197 self.operand2.generate_disposal_code(code)
4199 def annotate(self, code):
4200 self.operand1.annotate(code)
4201 self.operand2.annotate(code)
4202 if self.cascade:
4203 self.cascade.annotate(code)
4206 class CascadedCmpNode(Node, CmpNode):
4207 # A CascadedCmpNode is not a complete expression node. It
4208 # hangs off the side of another comparison node, shares
4209 # its left operand with that node, and shares its result
4210 # with the PrimaryCmpNode at the head of the chain.
4212 # operator string
4213 # operand2 ExprNode
4214 # cascade CascadedCmpNode
4216 child_attrs = ['operand2', 'cascade']
4218 cascade = None
4220 def analyse_types(self, env, operand1):
4221 self.operand2.analyse_types(env)
4222 if self.cascade:
4223 self.cascade.analyse_types(env, self.operand2)
4225 def check_operand_types(self, env, operand1):
4226 self.check_types(env,
4227 operand1, self.operator, self.operand2)
4228 if self.cascade:
4229 self.cascade.check_operand_types(env, self.operand2)
4231 def has_python_operands(self):
4232 return self.operand2.type.is_pyobject
4234 def coerce_operands_to_pyobjects(self, env):
4235 self.operand2 = self.operand2.coerce_to_pyobject(env)
4236 if self.cascade:
4237 self.cascade.coerce_operands_to_pyobjects(env)
4239 def has_int_operands(self):
4240 return self.operand2.type.is_int
4242 def coerce_chars_to_ints(self, env):
4243 if self.operand2.type.is_string and isinstance(self.operand2, StringNode):
4244 self.operand2 = self.operand2.coerce_to(PyrexTypes.c_uchar_type, env)
4246 def coerce_cascaded_operands_to_temp(self, env):
4247 if self.cascade:
4248 #self.operand2 = self.operand2.coerce_to_temp(env) #CTT
4249 self.operand2 = self.operand2.coerce_to_simple(env)
4250 self.cascade.coerce_cascaded_operands_to_temp(env)
4252 def allocate_subexpr_temps(self, env):
4253 self.operand2.allocate_temps(env)
4254 if self.cascade:
4255 self.cascade.allocate_subexpr_temps(env)
4257 def release_subexpr_temps(self, env):
4258 self.operand2.release_temp(env)
4259 if self.cascade:
4260 self.cascade.release_subexpr_temps(env)
4262 def generate_evaluation_code(self, code, result, operand1):
4263 if self.type.is_pyobject:
4264 code.putln("if (__Pyx_PyObject_IsTrue(%s)) {" % result)
4265 else:
4266 code.putln("if (%s) {" % result)
4267 self.operand2.generate_evaluation_code(code)
4268 self.generate_operation_code(code, result,
4269 operand1, self.operator, self.operand2)
4270 if self.cascade:
4271 self.cascade.generate_evaluation_code(
4272 code, result, self.operand2)
4273 # Cascaded cmp result is always temp
4274 self.operand2.generate_disposal_code(code)
4275 code.putln("}")
4277 def annotate(self, code):
4278 self.operand2.annotate(code)
4279 if self.cascade:
4280 self.cascade.annotate(code)
4283 binop_node_classes = {
4284 "or": BoolBinopNode,
4285 "and": BoolBinopNode,
4286 "|": IntBinopNode,
4287 "^": IntBinopNode,
4288 "&": IntBinopNode,
4289 "<<": IntBinopNode,
4290 ">>": IntBinopNode,
4291 "+": AddNode,
4292 "-": SubNode,
4293 "*": MulNode,
4294 "/": NumBinopNode,
4295 "//": FloorDivNode,
4296 "%": ModNode,
4297 "**": PowNode
4300 def binop_node(pos, operator, operand1, operand2):
4301 # Construct binop node of appropriate class for
4302 # given operator.
4303 return binop_node_classes[operator](pos,
4304 operator = operator,
4305 operand1 = operand1,
4306 operand2 = operand2)
4308 #-------------------------------------------------------------------
4310 # Coercion nodes
4312 # Coercion nodes are special in that they are created during
4313 # the analyse_types phase of parse tree processing.
4314 # Their __init__ methods consequently incorporate some aspects
4315 # of that phase.
4317 #-------------------------------------------------------------------
4319 class CoercionNode(ExprNode):
4320 # Abstract base class for coercion nodes.
4322 # arg ExprNode node being coerced
4324 subexprs = ['arg']
4326 def __init__(self, arg):
4327 self.pos = arg.pos
4328 self.arg = arg
4329 if debug_coercion:
4330 print("%s Coercing %s" % (self, self.arg))
4332 def annotate(self, code):
4333 self.arg.annotate(code)
4334 if self.arg.type != self.type:
4335 file, line, col = self.pos
4336 code.annotate((file, line, col-1), AnnotationItem(style='coerce', tag='coerce', text='[%s] to [%s]' % (self.arg.type, self.type)))
4339 class CastNode(CoercionNode):
4340 # Wrap a node in a C type cast.
4342 def __init__(self, arg, new_type):
4343 CoercionNode.__init__(self, arg)
4344 self.type = new_type
4346 def calculate_result_code(self):
4347 return self.arg.result_as(self.type)
4349 def generate_result_code(self, code):
4350 self.arg.generate_result_code(code)
4353 class PyTypeTestNode(CoercionNode):
4354 # This node is used to check that a generic Python
4355 # object is an instance of a particular extension type.
4356 # This node borrows the result of its argument node.
4358 def __init__(self, arg, dst_type, env):
4359 # The arg is know to be a Python object, and
4360 # the dst_type is known to be an extension type.
4361 assert dst_type.is_extension_type or dst_type.is_builtin_type, "PyTypeTest on non extension type"
4362 CoercionNode.__init__(self, arg)
4363 self.type = dst_type
4364 self.gil_check(env)
4365 self.result_ctype = arg.ctype()
4366 env.use_utility_code(type_test_utility_code)
4368 gil_message = "Python type test"
4370 def analyse_types(self, env):
4371 pass
4373 def result_in_temp(self):
4374 return self.arg.result_in_temp()
4376 def is_ephemeral(self):
4377 return self.arg.is_ephemeral()
4379 def calculate_result_code(self):
4380 return self.arg.result()
4382 def generate_result_code(self, code):
4383 if self.type.typeobj_is_available():
4384 code.putln(
4385 "if (!(%s)) %s" % (
4386 self.type.type_test_code(self.arg.py_result()),
4387 code.error_goto(self.pos)))
4388 else:
4389 error(self.pos, "Cannot test type of extern C class "
4390 "without type object name specification")
4392 def generate_post_assignment_code(self, code):
4393 self.arg.generate_post_assignment_code(code)
4396 class CoerceToPyTypeNode(CoercionNode):
4397 # This node is used to convert a C data type
4398 # to a Python object.
4400 def __init__(self, arg, env):
4401 CoercionNode.__init__(self, arg)
4402 self.type = py_object_type
4403 self.gil_check(env)
4404 self.is_temp = 1
4405 if not arg.type.to_py_function or not arg.type.create_convert_utility_code(env):
4406 error(arg.pos,
4407 "Cannot convert '%s' to Python object" % arg.type)
4409 gil_message = "Converting to Python object"
4411 def coerce_to_boolean(self, env):
4412 return self.arg.coerce_to_boolean(env)
4414 def analyse_types(self, env):
4415 # The arg is always already analysed
4416 pass
4418 def generate_result_code(self, code):
4419 function = self.arg.type.to_py_function
4420 code.putln('%s = %s(%s); %s' % (
4421 self.result(),
4422 function,
4423 self.arg.result(),
4424 code.error_goto_if_null(self.result(), self.pos)))
4427 class CoerceFromPyTypeNode(CoercionNode):
4428 # This node is used to convert a Python object
4429 # to a C data type.
4431 def __init__(self, result_type, arg, env):
4432 CoercionNode.__init__(self, arg)
4433 self.type = result_type
4434 self.is_temp = 1
4435 if not result_type.from_py_function:
4436 error(arg.pos,
4437 "Cannot convert Python object to '%s'" % result_type)
4438 if self.type.is_string and self.arg.is_ephemeral():
4439 error(arg.pos,
4440 "Obtaining char * from temporary Python value")
4442 def analyse_types(self, env):
4443 # The arg is always already analysed
4444 pass
4446 def generate_result_code(self, code):
4447 function = self.type.from_py_function
4448 operand = self.arg.py_result()
4449 rhs = "%s(%s)" % (function, operand)
4450 if self.type.is_enum:
4451 rhs = typecast(self.type, c_long_type, rhs)
4452 code.putln('%s = %s; %s' % (
4453 self.result(),
4454 rhs,
4455 code.error_goto_if(self.type.error_condition(self.result()), self.pos)))
4458 class CoerceToBooleanNode(CoercionNode):
4459 # This node is used when a result needs to be used
4460 # in a boolean context.
4462 def __init__(self, arg, env):
4463 CoercionNode.__init__(self, arg)
4464 self.type = PyrexTypes.c_bint_type
4465 if arg.type.is_pyobject:
4466 if env.nogil:
4467 self.gil_error()
4468 self.is_temp = 1
4470 gil_message = "Truth-testing Python object"
4472 def check_const(self):
4473 if self.is_temp:
4474 self.not_const()
4475 self.arg.check_const()
4477 def calculate_result_code(self):
4478 return "(%s != 0)" % self.arg.result()
4480 def generate_result_code(self, code):
4481 if self.arg.type.is_pyobject:
4482 code.putln(
4483 "%s = __Pyx_PyObject_IsTrue(%s); %s" % (
4484 self.result(),
4485 self.arg.py_result(),
4486 code.error_goto_if_neg(self.result(), self.pos)))
4489 class CoerceToTempNode(CoercionNode):
4490 # This node is used to force the result of another node
4491 # to be stored in a temporary. It is only used if the
4492 # argument node's result is not already in a temporary.
4494 def __init__(self, arg, env):
4495 CoercionNode.__init__(self, arg)
4496 self.type = self.arg.type
4497 self.is_temp = 1
4498 if self.type.is_pyobject:
4499 self.gil_check(env)
4500 self.result_ctype = py_object_type
4502 gil_message = "Creating temporary Python reference"
4504 def analyse_types(self, env):
4505 # The arg is always already analysed
4506 pass
4508 def coerce_to_boolean(self, env):
4509 self.arg = self.arg.coerce_to_boolean(env)
4510 self.type = self.arg.type
4511 self.result_ctype = self.type
4512 return self
4514 def generate_result_code(self, code):
4515 #self.arg.generate_evaluation_code(code) # Already done
4516 # by generic generate_subexpr_evaluation_code!
4517 code.putln("%s = %s;" % (
4518 self.result(), self.arg.result_as(self.ctype())))
4519 if self.type.is_pyobject:
4520 code.put_incref(self.result(), self.ctype())
4523 class CloneNode(CoercionNode):
4524 # This node is employed when the result of another node needs
4525 # to be used multiple times. The argument node's result must
4526 # be in a temporary. This node "borrows" the result from the
4527 # argument node, and does not generate any evaluation or
4528 # disposal code for it. The original owner of the argument
4529 # node is responsible for doing those things.
4531 subexprs = [] # Arg is not considered a subexpr
4533 def __init__(self, arg):
4534 CoercionNode.__init__(self, arg)
4535 if hasattr(arg, 'type'):
4536 self.type = arg.type
4537 self.result_ctype = arg.result_ctype
4538 if hasattr(arg, 'entry'):
4539 self.entry = arg.entry
4541 def result(self):
4542 return self.arg.result()
4544 def analyse_types(self, env):
4545 self.type = self.arg.type
4546 self.result_ctype = self.arg.result_ctype
4547 self.is_temp = 1
4548 if hasattr(self.arg, 'entry'):
4549 self.entry = self.arg.entry
4551 def generate_evaluation_code(self, code):
4552 pass
4554 def generate_result_code(self, code):
4555 pass
4557 def generate_disposal_code(self, code):
4558 pass
4560 def allocate_temps(self, env):
4561 pass
4563 def release_temp(self, env):
4564 pass
4566 class PersistentNode(ExprNode):
4567 # A PersistentNode is like a CloneNode except it handles the temporary
4568 # allocation itself by keeping track of the number of times it has been
4569 # used.
4571 subexprs = ["arg"]
4572 temp_counter = 0
4573 generate_counter = 0
4574 analyse_counter = 0
4575 result_code = None
4577 def __init__(self, arg, uses):
4578 self.pos = arg.pos
4579 self.arg = arg
4580 self.uses = uses
4582 def analyse_types(self, env):
4583 if self.analyse_counter == 0:
4584 self.arg.analyse_types(env)
4585 self.type = self.arg.type
4586 self.result_ctype = self.arg.result_ctype
4587 self.is_temp = 1
4588 self.analyse_counter += 1
4590 def calculate_result_code(self):
4591 return self.result()
4593 def generate_evaluation_code(self, code):
4594 if self.generate_counter == 0:
4595 self.arg.generate_evaluation_code(code)
4596 code.putln("%s = %s;" % (
4597 self.result(), self.arg.result_as(self.ctype())))
4598 if self.type.is_pyobject:
4599 code.put_incref(self.result(), self.ctype())
4600 self.arg.generate_disposal_code(code)
4601 self.generate_counter += 1
4603 def generate_disposal_code(self, code):
4604 if self.generate_counter == self.uses:
4605 if self.type.is_pyobject:
4606 code.put_decref_clear(self.result(), self.ctype())
4608 def allocate_temps(self, env, result=None):
4609 if self.temp_counter == 0:
4610 self.arg.allocate_temps(env)
4611 self.allocate_temp(env, result)
4612 self.arg.release_temp(env)
4613 self.temp_counter += 1
4615 def allocate_temp(self, env, result=None):
4616 if result is None:
4617 self.result_code = env.allocate_temp(self.type)
4618 else:
4619 self.result_code = result
4621 def release_temp(self, env):
4622 if self.temp_counter == self.uses:
4623 env.release_temp(self.result())
4625 #------------------------------------------------------------------------------------
4627 # Runtime support code
4629 #------------------------------------------------------------------------------------
4631 get_name_interned_utility_code = [
4632 """
4633 static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/
4634 ""","""
4635 static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) {
4636 PyObject *result;
4637 result = PyObject_GetAttr(dict, name);
4638 if (!result)
4639 PyErr_SetObject(PyExc_NameError, name);
4640 return result;
4642 """]
4644 #------------------------------------------------------------------------------------
4646 import_utility_code = [
4647 """
4648 static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/
4649 ""","""
4650 static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) {
4651 PyObject *__import__ = 0;
4652 PyObject *empty_list = 0;
4653 PyObject *module = 0;
4654 PyObject *global_dict = 0;
4655 PyObject *empty_dict = 0;
4656 PyObject *list;
4657 __import__ = PyObject_GetAttrString(%(BUILTINS)s, "__import__");
4658 if (!__import__)
4659 goto bad;
4660 if (from_list)
4661 list = from_list;
4662 else {
4663 empty_list = PyList_New(0);
4664 if (!empty_list)
4665 goto bad;
4666 list = empty_list;
4668 global_dict = PyModule_GetDict(%(GLOBALS)s);
4669 if (!global_dict)
4670 goto bad;
4671 empty_dict = PyDict_New();
4672 if (!empty_dict)
4673 goto bad;
4674 module = PyObject_CallFunction(__import__, "OOOO",
4675 name, global_dict, empty_dict, list);
4676 bad:
4677 Py_XDECREF(empty_list);
4678 Py_XDECREF(__import__);
4679 Py_XDECREF(empty_dict);
4680 return module;
4682 """ % {
4683 "BUILTINS": Naming.builtins_cname,
4684 "GLOBALS": Naming.module_cname,
4685 }]
4687 #------------------------------------------------------------------------------------
4689 get_exception_utility_code = [
4690 """
4691 static PyObject *__Pyx_GetExcValue(void); /*proto*/
4692 ""","""
4693 static PyObject *__Pyx_GetExcValue(void) {
4694 PyObject *type = 0, *value = 0, *tb = 0;
4695 PyObject *tmp_type, *tmp_value, *tmp_tb;
4696 PyObject *result = 0;
4697 PyThreadState *tstate = PyThreadState_Get();
4698 PyErr_Fetch(&type, &value, &tb);
4699 PyErr_NormalizeException(&type, &value, &tb);
4700 if (PyErr_Occurred())
4701 goto bad;
4702 if (!value) {
4703 value = Py_None;
4704 Py_INCREF(value);
4706 tmp_type = tstate->exc_type;
4707 tmp_value = tstate->exc_value;
4708 tmp_tb = tstate->exc_traceback;
4709 tstate->exc_type = type;
4710 tstate->exc_value = value;
4711 tstate->exc_traceback = tb;
4712 /* Make sure tstate is in a consistent state when we XDECREF
4713 these objects (XDECREF may run arbitrary code). */
4714 Py_XDECREF(tmp_type);
4715 Py_XDECREF(tmp_value);
4716 Py_XDECREF(tmp_tb);
4717 result = value;
4718 Py_XINCREF(result);
4719 type = 0;
4720 value = 0;
4721 tb = 0;
4722 bad:
4723 Py_XDECREF(type);
4724 Py_XDECREF(value);
4725 Py_XDECREF(tb);
4726 return result;
4728 """]
4730 #------------------------------------------------------------------------------------
4732 unpacking_utility_code = [
4733 """
4734 static PyObject *__Pyx_UnpackItem(PyObject *, Py_ssize_t index); /*proto*/
4735 static int __Pyx_EndUnpack(PyObject *); /*proto*/
4736 ""","""
4737 static PyObject *__Pyx_UnpackItem(PyObject *iter, Py_ssize_t index) {
4738 PyObject *item;
4739 if (!(item = PyIter_Next(iter))) {
4740 if (!PyErr_Occurred()) {
4741 PyErr_Format(PyExc_ValueError,
4742 #if PY_VERSION_HEX < 0x02050000
4743 "need more than %d values to unpack", (int)index);
4744 #else
4745 "need more than %zd values to unpack", index);
4746 #endif
4749 return item;
4752 static int __Pyx_EndUnpack(PyObject *iter) {
4753 PyObject *item;
4754 if ((item = PyIter_Next(iter))) {
4755 Py_DECREF(item);
4756 PyErr_SetString(PyExc_ValueError, "too many values to unpack");
4757 return -1;
4759 else if (!PyErr_Occurred())
4760 return 0;
4761 else
4762 return -1;
4764 """]
4766 #------------------------------------------------------------------------------------
4768 type_test_utility_code = [
4769 """
4770 static int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); /*proto*/
4771 ""","""
4772 static int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
4773 if (!type) {
4774 PyErr_Format(PyExc_SystemError, "Missing type object");
4775 return 0;
4777 if (obj == Py_None || PyObject_TypeCheck(obj, type))
4778 return 1;
4779 PyErr_Format(PyExc_TypeError, "Cannot convert %s to %s",
4780 Py_TYPE(obj)->tp_name, type->tp_name);
4781 return 0;
4783 """]
4785 #------------------------------------------------------------------------------------
4787 create_class_utility_code = [
4788 """
4789 static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, char *modname); /*proto*/
4790 ""","""
4791 static PyObject *__Pyx_CreateClass(
4792 PyObject *bases, PyObject *dict, PyObject *name, char *modname)
4794 PyObject *py_modname;
4795 PyObject *result = 0;
4797 #if PY_MAJOR_VERSION < 3
4798 py_modname = PyString_FromString(modname);
4799 #else
4800 py_modname = PyUnicode_FromString(modname);
4801 #endif
4802 if (!py_modname)
4803 goto bad;
4804 if (PyDict_SetItemString(dict, "__module__", py_modname) < 0)
4805 goto bad;
4806 #if PY_MAJOR_VERSION < 3
4807 result = PyClass_New(bases, dict, name);
4808 #else
4809 result = PyObject_CallFunctionObjArgs((PyObject *)&PyType_Type, name, bases, dict, NULL);
4810 #endif
4811 bad:
4812 Py_XDECREF(py_modname);
4813 return result;
4815 """]
4817 #------------------------------------------------------------------------------------
4819 cpp_exception_utility_code = [
4820 """
4821 #ifndef __Pyx_CppExn2PyErr
4822 static void __Pyx_CppExn2PyErr() {
4823 try {
4824 if (PyErr_Occurred())
4825 ; // let the latest Python exn pass through and ignore the current one
4826 else
4827 throw;
4828 } catch (const std::out_of_range& exn) {
4829 // catch out_of_range explicitly so the proper Python exn may be raised
4830 PyErr_SetString(PyExc_IndexError, exn.what());
4831 } catch (const std::exception& exn) {
4832 PyErr_SetString(PyExc_RuntimeError, exn.what());
4834 catch (...)
4836 PyErr_SetString(PyExc_RuntimeError, "Unknown exception");
4839 #endif
4840 """,""]
4842 #------------------------------------------------------------------------------------
4844 append_utility_code = [
4845 """
4846 static INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
4847 if (likely(PyList_CheckExact(L))) {
4848 if (PyList_Append(L, x) < 0) return NULL;
4849 Py_INCREF(Py_None);
4850 return Py_None; // this is just to have an accurate signature
4852 else {
4853 return PyObject_CallMethod(L, "append", "(O)", x);
4856 """,""
4859 #------------------------------------------------------------------------------------
4861 # If the is_unsigned flag is set, we need to do some extra work to make
4862 # sure the index doesn't become negative.
4864 getitem_int_utility_code = [
4865 """
4866 static INLINE PyObject *__Pyx_GetItemInt(PyObject *o, Py_ssize_t i, int is_unsigned) {
4867 PyObject *r;
4868 if (PyList_CheckExact(o) && 0 <= i && i < PyList_GET_SIZE(o)) {
4869 r = PyList_GET_ITEM(o, i);
4870 Py_INCREF(r);
4872 else if (PyTuple_CheckExact(o) && 0 <= i && i < PyTuple_GET_SIZE(o)) {
4873 r = PyTuple_GET_ITEM(o, i);
4874 Py_INCREF(r);
4876 else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_item && (likely(i >= 0) || !is_unsigned))
4877 r = PySequence_GetItem(o, i);
4878 else {
4879 PyObject *j = (likely(i >= 0) || !is_unsigned) ? PyInt_FromLong(i) : PyLong_FromUnsignedLongLong((sizeof(unsigned long long) > sizeof(Py_ssize_t) ? (1ULL << (sizeof(Py_ssize_t)*8)) : 0) + i);
4880 if (!j)
4881 return 0;
4882 r = PyObject_GetItem(o, j);
4883 Py_DECREF(j);
4885 return r;
4887 """,
4888 """
4889 """]
4891 #------------------------------------------------------------------------------------
4893 setitem_int_utility_code = [
4894 """
4895 static INLINE int __Pyx_SetItemInt(PyObject *o, Py_ssize_t i, PyObject *v, int is_unsigned) {
4896 int r;
4897 if (PyList_CheckExact(o) && 0 <= i && i < PyList_GET_SIZE(o)) {
4898 Py_DECREF(PyList_GET_ITEM(o, i));
4899 Py_INCREF(v);
4900 PyList_SET_ITEM(o, i, v);
4901 return 1;
4903 else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_ass_item && (likely(i >= 0) || !is_unsigned))
4904 r = PySequence_SetItem(o, i, v);
4905 else {
4906 PyObject *j = (likely(i >= 0) || !is_unsigned) ? PyInt_FromLong(i) : PyLong_FromUnsignedLongLong((sizeof(unsigned long long) > sizeof(Py_ssize_t) ? (1ULL << (sizeof(Py_ssize_t)*8)) : 0) + i);
4907 if (!j)
4908 return -1;
4909 r = PyObject_SetItem(o, j, v);
4910 Py_DECREF(j);
4912 return r;
4914 """,
4915 """
4916 """]
4917 #------------------------------------------------------------------------------------
4919 raise_noneattr_error_utility_code = [
4920 """
4921 static INLINE void __Pyx_RaiseNoneAttributeError(char* attrname);
4922 """, """
4923 static INLINE void __Pyx_RaiseNoneAttributeError(char* attrname) {
4924 PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", attrname);
4926 """]
4928 raise_noneindex_error_utility_code = [
4929 """
4930 static INLINE void __Pyx_RaiseNoneIndexingError();
4931 """, """
4932 static INLINE void __Pyx_RaiseNoneIndexingError() {
4933 PyErr_SetString(PyExc_TypeError, "'NoneType' object is unsubscriptable");
4935 """]