Cython has moved to github.

cython-devel

view Cython/Compiler/Nodes.py @ 1500:c1a7180ac974

moved iter-range() optimisation into a transform (worth a review)
author Stefan Behnel <scoder@users.berlios.de>
date Wed Dec 17 22:29:11 2008 +0100 (3 years ago)
parents 4ad4c8530455
children 27f0d0f718a5
line source
1 #
2 # Pyrex - Parse tree nodes
3 #
5 import string, sys, os, time, copy
7 import Code
8 import Builtin
9 from Errors import error, warning, InternalError
10 import Naming
11 import PyrexTypes
12 import TypeSlots
13 from PyrexTypes import py_object_type, error_type, CTypedefType, CFuncType
14 from Symtab import ModuleScope, LocalScope, GeneratorLocalScope, \
15 StructOrUnionScope, PyClassScope, CClassScope
16 from Cython.Utils import open_new_file, replace_suffix, UtilityCode
17 from StringEncoding import EncodedString, escape_byte_string, split_docstring
18 import Options
19 import ControlFlow
21 from DebugFlags import debug_disposal_code
23 absolute_path_length = 0
25 def relative_position(pos):
26 """
27 We embed the relative filename in the generated C file, since we
28 don't want to have to regnerate and compile all the source code
29 whenever the Python install directory moves (which could happen,
30 e.g,. when distributing binaries.)
32 INPUT:
33 a position tuple -- (absolute filename, line number column position)
35 OUTPUT:
36 relative filename
37 line number
39 AUTHOR: William Stein
40 """
41 global absolute_path_length
42 if absolute_path_length==0:
43 absolute_path_length = len(os.path.abspath(os.getcwd()))
44 return (pos[0].get_filenametable_entry()[absolute_path_length+1:], pos[1])
46 def embed_position(pos, docstring):
47 if not Options.embed_pos_in_docstring:
48 return docstring
49 pos_line = u'File: %s (starting at line %s)' % relative_position(pos)
50 if docstring is None:
51 # unicode string
52 return EncodedString(pos_line)
54 # make sure we can encode the filename in the docstring encoding
55 # otherwise make the docstring a unicode string
56 encoding = docstring.encoding
57 if encoding is not None:
58 try:
59 encoded_bytes = pos_line.encode(encoding)
60 except UnicodeEncodeError:
61 encoding = None
63 if not docstring:
64 # reuse the string encoding of the original docstring
65 doc = EncodedString(pos_line)
66 else:
67 doc = EncodedString(pos_line + u'\n' + docstring)
68 doc.encoding = encoding
69 return doc
71 class Node(object):
72 # pos (string, int, int) Source file position
73 # is_name boolean Is a NameNode
74 # is_literal boolean Is a ConstNode
76 is_name = 0
77 is_literal = 0
78 temps = None
80 # All descandants should set child_attrs to a list of the attributes
81 # containing nodes considered "children" in the tree. Each such attribute
82 # can either contain a single node or a list of nodes. See Visitor.py.
83 child_attrs = None
85 def __init__(self, pos, **kw):
86 self.pos = pos
87 self.__dict__.update(kw)
89 gil_message = "Operation"
91 def gil_check(self, env):
92 if env.nogil:
93 self.gil_error()
95 def gil_error(self):
96 error(self.pos, "%s not allowed without gil" % self.gil_message)
98 def clone_node(self):
99 """Clone the node. This is defined as a shallow copy, except for member lists
100 amongst the child attributes (from get_child_accessors) which are also
101 copied. Lists containing child nodes are thus seen as a way for the node
102 to hold multiple children directly; the list is not treated as a seperate
103 level in the tree."""
104 result = copy.copy(self)
105 for attrname in result.child_attrs:
106 value = getattr(result, attrname)
107 if isinstance(value, list):
108 setattr(result, attrname, [x for x in value])
109 return result
112 #
113 # There are 4 phases of parse tree processing, applied in order to
114 # all the statements in a given scope-block:
115 #
116 # (0) analyse_control_flow
117 # Create the control flow tree into which state can be asserted and
118 # queried.
119 #
120 # (1) analyse_declarations
121 # Make symbol table entries for all declarations at the current
122 # level, both explicit (def, cdef, etc.) and implicit (assignment
123 # to an otherwise undeclared name).
124 #
125 # (2) analyse_expressions
126 # Determine the result types of expressions and fill in the
127 # 'type' attribute of each ExprNode. Insert coercion nodes into the
128 # tree where needed to convert to and from Python objects.
129 # Allocate temporary locals for intermediate results. Fill
130 # in the 'result_code' attribute of each ExprNode with a C code
131 # fragment.
132 #
133 # (3) generate_code
134 # Emit C code for all declarations, statements and expressions.
135 # Recursively applies the 3 processing phases to the bodies of
136 # functions.
137 #
139 def analyse_control_flow(self, env):
140 pass
142 def analyse_declarations(self, env):
143 pass
145 def analyse_expressions(self, env):
146 raise InternalError("analyse_expressions not implemented for %s" % \
147 self.__class__.__name__)
149 def generate_code(self, code):
150 raise InternalError("generate_code not implemented for %s" % \
151 self.__class__.__name__)
153 def annotate(self, code):
154 # mro does the wrong thing
155 if isinstance(self, BlockNode):
156 self.body.annotate(code)
158 def end_pos(self):
159 if not self.child_attrs:
160 return self.pos
161 try:
162 return self._end_pos
163 except AttributeError:
164 pos = self.pos
165 for attr in self.child_attrs:
166 child = getattr(self, attr)
167 # Sometimes lists, sometimes nodes
168 if child is None:
169 pass
170 elif isinstance(child, list):
171 for c in child:
172 pos = max(pos, c.end_pos())
173 else:
174 pos = max(pos, child.end_pos())
175 self._end_pos = pos
176 return pos
178 def dump(self, level=0, filter_out=("pos",), cutoff=100, encountered=None):
179 if cutoff == 0:
180 return "<...nesting level cutoff...>"
181 if encountered is None:
182 encountered = set()
183 if id(self) in encountered:
184 return "<%s (%d) -- already output>" % (self.__class__.__name__, id(self))
185 encountered.add(id(self))
187 def dump_child(x, level):
188 if isinstance(x, Node):
189 return x.dump(level, filter_out, cutoff-1, encountered)
190 elif isinstance(x, list):
191 return "[%s]" % ", ".join([dump_child(item, level) for item in x])
192 else:
193 return repr(x)
196 attrs = [(key, value) for key, value in self.__dict__.iteritems() if key not in filter_out]
197 if len(attrs) == 0:
198 return "<%s (%d)>" % (self.__class__.__name__, id(self))
199 else:
200 indent = " " * level
201 res = "<%s (%d)\n" % (self.__class__.__name__, id(self))
202 for key, value in attrs:
203 res += "%s %s: %s\n" % (indent, key, dump_child(value, level + 1))
204 res += "%s>" % indent
205 return res
207 class CompilerDirectivesNode(Node):
208 """
209 Sets compiler directives for the children nodes
210 """
211 # directives {string:value} A dictionary holding the right value for
212 # *all* possible directives.
213 # body Node
214 child_attrs = ["body"]
216 def analyse_control_flow(self, env):
217 old = env.directives
218 env.directives = self.directives
219 self.body.analyse_control_flow(env)
220 env.directives = old
222 def analyse_declarations(self, env):
223 old = env.directives
224 env.directives = self.directives
225 self.body.analyse_declarations(env)
226 env.directives = old
228 def analyse_expressions(self, env):
229 old = env.directives
230 env.directives = self.directives
231 self.body.analyse_expressions(env)
232 env.directives = old
234 def generate_function_definitions(self, env, code):
235 env_old = env.directives
236 code_old = code.globalstate.directives
237 code.globalstate.directives = self.directives
238 self.body.generate_function_definitions(env, code)
239 env.directives = env_old
240 code.globalstate.directives = code_old
242 def generate_execution_code(self, code):
243 old = code.globalstate.directives
244 code.globalstate.directives = self.directives
245 self.body.generate_execution_code(code)
246 code.globalstate.directives = old
248 def annotate(self, code):
249 old = code.globalstate.directives
250 code.globalstate.directives = self.directives
251 self.body.annotate(code)
252 code.globalstate.directives = old
254 class BlockNode(object):
255 # Mixin class for nodes representing a declaration block.
257 def generate_const_definitions(self, env, code):
258 if env.const_entries:
259 for entry in env.const_entries:
260 if not entry.is_interned:
261 code.globalstate.add_const_definition(entry)
263 def generate_interned_string_decls(self, env, code):
264 entries = env.global_scope().new_interned_string_entries
265 if entries:
266 for entry in entries:
267 code.globalstate.add_interned_string_decl(entry)
268 del entries[:]
270 def generate_py_string_decls(self, env, code):
271 if env is None:
272 return # earlier error
273 entries = env.pystring_entries
274 if entries:
275 for entry in entries:
276 if not entry.is_interned:
277 code.globalstate.add_py_string_decl(entry)
279 def generate_interned_num_decls(self, env, code):
280 # Flush accumulated interned nums from the global scope
281 # and generate declarations for them.
282 genv = env.global_scope()
283 entries = genv.interned_nums
284 if entries:
285 for entry in entries:
286 code.globalstate.add_interned_num_decl(entry)
287 del entries[:]
289 def generate_cached_builtins_decls(self, env, code):
290 entries = env.global_scope().undeclared_cached_builtins
291 for entry in entries:
292 code.globalstate.add_cached_builtin_decl(entry)
293 del entries[:]
296 class StatListNode(Node):
297 # stats a list of StatNode
299 child_attrs = ["stats"]
301 def create_analysed(pos, env, *args, **kw):
302 node = StatListNode(pos, *args, **kw)
303 return node # No node-specific analysis necesarry
304 create_analysed = staticmethod(create_analysed)
306 def analyse_control_flow(self, env):
307 for stat in self.stats:
308 stat.analyse_control_flow(env)
310 def analyse_declarations(self, env):
311 #print "StatListNode.analyse_declarations" ###
312 for stat in self.stats:
313 stat.analyse_declarations(env)
315 def analyse_expressions(self, env):
316 #print "StatListNode.analyse_expressions" ###
317 for stat in self.stats:
318 stat.analyse_expressions(env)
320 def generate_function_definitions(self, env, code):
321 #print "StatListNode.generate_function_definitions" ###
322 for stat in self.stats:
323 stat.generate_function_definitions(env, code)
325 def generate_execution_code(self, code):
326 #print "StatListNode.generate_execution_code" ###
327 for stat in self.stats:
328 code.mark_pos(stat.pos)
329 stat.generate_execution_code(code)
331 def annotate(self, code):
332 for stat in self.stats:
333 stat.annotate(code)
336 class StatNode(Node):
337 #
338 # Code generation for statements is split into the following subphases:
339 #
340 # (1) generate_function_definitions
341 # Emit C code for the definitions of any structs,
342 # unions, enums and functions defined in the current
343 # scope-block.
344 #
345 # (2) generate_execution_code
346 # Emit C code for executable statements.
347 #
349 def generate_function_definitions(self, env, code):
350 pass
352 def generate_execution_code(self, code):
353 raise InternalError("generate_execution_code not implemented for %s" % \
354 self.__class__.__name__)
357 class CDefExternNode(StatNode):
358 # include_file string or None
359 # body StatNode
361 child_attrs = ["body"]
363 def analyse_declarations(self, env):
364 if self.include_file:
365 env.add_include_file(self.include_file)
366 old_cinclude_flag = env.in_cinclude
367 env.in_cinclude = 1
368 self.body.analyse_declarations(env)
369 env.in_cinclude = old_cinclude_flag
371 def analyse_expressions(self, env):
372 pass
374 def generate_execution_code(self, code):
375 pass
377 def annotate(self, code):
378 self.body.annotate(code)
381 class CDeclaratorNode(Node):
382 # Part of a C declaration.
383 #
384 # Processing during analyse_declarations phase:
385 #
386 # analyse
387 # Returns (name, type) pair where name is the
388 # CNameDeclaratorNode of the name being declared
389 # and type is the type it is being declared as.
390 #
391 # calling_convention string Calling convention of CFuncDeclaratorNode
392 # for which this is a base
394 child_attrs = []
396 calling_convention = ""
399 class CNameDeclaratorNode(CDeclaratorNode):
400 # name string The Pyrex name being declared
401 # cname string or None C name, if specified
402 # default ExprNode or None the value assigned on declaration
404 child_attrs = ['default']
406 default = None
408 def analyse(self, base_type, env, nonempty = 0):
409 if nonempty and self.name == '':
410 # May have mistaken the name for the type.
411 if base_type.is_ptr or base_type.is_array or base_type.is_buffer:
412 error(self.pos, "Missing argument name")
413 elif base_type.is_void:
414 error(self.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
415 else:
416 self.name = base_type.declaration_code("", for_display=1, pyrex=1)
417 base_type = py_object_type
418 self.type = base_type
419 return self, base_type
421 class CPtrDeclaratorNode(CDeclaratorNode):
422 # base CDeclaratorNode
424 child_attrs = ["base"]
426 def analyse(self, base_type, env, nonempty = 0):
427 if base_type.is_pyobject:
428 error(self.pos,
429 "Pointer base type cannot be a Python object")
430 ptr_type = PyrexTypes.c_ptr_type(base_type)
431 return self.base.analyse(ptr_type, env, nonempty = nonempty)
433 class CArrayDeclaratorNode(CDeclaratorNode):
434 # base CDeclaratorNode
435 # dimension ExprNode
437 child_attrs = ["base", "dimension"]
439 def analyse(self, base_type, env, nonempty = 0):
440 if self.dimension:
441 self.dimension.analyse_const_expression(env)
442 if not self.dimension.type.is_int:
443 error(self.dimension.pos, "Array dimension not integer")
444 size = self.dimension.result()
445 try:
446 size = int(size)
447 except ValueError:
448 # runtime constant?
449 pass
450 else:
451 size = None
452 if not base_type.is_complete():
453 error(self.pos,
454 "Array element type '%s' is incomplete" % base_type)
455 if base_type.is_pyobject:
456 error(self.pos,
457 "Array element cannot be a Python object")
458 if base_type.is_cfunction:
459 error(self.pos,
460 "Array element cannot be a function")
461 array_type = PyrexTypes.c_array_type(base_type, size)
462 return self.base.analyse(array_type, env, nonempty = nonempty)
465 class CFuncDeclaratorNode(CDeclaratorNode):
466 # base CDeclaratorNode
467 # args [CArgDeclNode]
468 # has_varargs boolean
469 # exception_value ConstNode
470 # exception_check boolean True if PyErr_Occurred check needed
471 # nogil boolean Can be called without gil
472 # with_gil boolean Acquire gil around function body
474 child_attrs = ["base", "args", "exception_value"]
476 overridable = 0
477 optional_arg_count = 0
479 def analyse(self, return_type, env, nonempty = 0):
480 if nonempty:
481 nonempty -= 1
482 func_type_args = []
483 for arg_node in self.args:
484 name_declarator, type = arg_node.analyse(env, nonempty = nonempty)
485 name = name_declarator.name
486 if name_declarator.cname:
487 error(self.pos,
488 "Function argument cannot have C name specification")
489 # Turn *[] argument into **
490 if type.is_array:
491 type = PyrexTypes.c_ptr_type(type.base_type)
492 # Catch attempted C-style func(void) decl
493 if type.is_void:
494 error(arg_node.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
495 # if type.is_pyobject and self.nogil:
496 # error(self.pos,
497 # "Function with Python argument cannot be declared nogil")
498 func_type_args.append(
499 PyrexTypes.CFuncTypeArg(name, type, arg_node.pos))
500 if arg_node.default:
501 self.optional_arg_count += 1
502 elif self.optional_arg_count:
503 error(self.pos, "Non-default argument follows default argument")
505 if self.optional_arg_count:
506 scope = StructOrUnionScope()
507 scope.declare_var('%sn' % Naming.pyrex_prefix, PyrexTypes.c_int_type, self.pos)
508 for arg in func_type_args[len(func_type_args)-self.optional_arg_count:]:
509 scope.declare_var(arg.name, arg.type, arg.pos, allow_pyobject = 1)
510 struct_cname = env.mangle(Naming.opt_arg_prefix, self.base.name)
511 self.op_args_struct = env.global_scope().declare_struct_or_union(name = struct_cname,
512 kind = 'struct',
513 scope = scope,
514 typedef_flag = 0,
515 pos = self.pos,
516 cname = struct_cname)
517 self.op_args_struct.defined_in_pxd = 1
518 self.op_args_struct.used = 1
520 exc_val = None
521 exc_check = 0
522 if return_type.is_pyobject \
523 and (self.exception_value or self.exception_check) \
524 and self.exception_check != '+':
525 error(self.pos,
526 "Exception clause not allowed for function returning Python object")
527 else:
528 if self.exception_value:
529 self.exception_value.analyse_const_expression(env)
530 if self.exception_check == '+':
531 exc_val_type = self.exception_value.type
532 if not exc_val_type.is_error and \
533 not exc_val_type.is_pyobject and \
534 not (exc_val_type.is_cfunction and not exc_val_type.return_type.is_pyobject and len(exc_val_type.args)==0):
535 error(self.exception_value.pos,
536 "Exception value must be a Python exception or cdef function with no arguments.")
537 exc_val = self.exception_value
538 else:
539 exc_val = self.exception_value.result()
540 if not return_type.assignable_from(self.exception_value.type):
541 error(self.exception_value.pos,
542 "Exception value incompatible with function return type")
543 exc_check = self.exception_check
544 if return_type.is_array:
545 error(self.pos,
546 "Function cannot return an array")
547 if return_type.is_cfunction:
548 error(self.pos,
549 "Function cannot return a function")
550 func_type = PyrexTypes.CFuncType(
551 return_type, func_type_args, self.has_varargs,
552 optional_arg_count = self.optional_arg_count,
553 exception_value = exc_val, exception_check = exc_check,
554 calling_convention = self.base.calling_convention,
555 nogil = self.nogil, with_gil = self.with_gil, is_overridable = self.overridable)
556 if self.optional_arg_count:
557 func_type.op_arg_struct = PyrexTypes.c_ptr_type(self.op_args_struct.type)
558 return self.base.analyse(func_type, env)
561 class CArgDeclNode(Node):
562 # Item in a function declaration argument list.
563 #
564 # base_type CBaseTypeNode
565 # declarator CDeclaratorNode
566 # not_none boolean Tagged with 'not None'
567 # default ExprNode or None
568 # default_entry Symtab.Entry Entry for the variable holding the default value
569 # default_result_code string cname or code fragment for default value
570 # is_self_arg boolean Is the "self" arg of an extension type method
571 # is_kw_only boolean Is a keyword-only argument
573 child_attrs = ["base_type", "declarator", "default"]
575 is_self_arg = 0
576 is_generic = 1
577 type = None
578 name_declarator = None
580 def analyse(self, env, nonempty = 0):
581 #print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ###
582 if self.type is None:
583 # The parser may missinterpret names as types...
584 # We fix that here.
585 if isinstance(self.declarator, CNameDeclaratorNode) and self.declarator.name == '':
586 if nonempty:
587 self.declarator.name = self.base_type.name
588 self.base_type.name = None
589 self.base_type.is_basic_c_type = False
590 could_be_name = True
591 else:
592 could_be_name = False
593 base_type = self.base_type.analyse(env, could_be_name = could_be_name)
594 if hasattr(self.base_type, 'arg_name') and self.base_type.arg_name:
595 self.declarator.name = self.base_type.arg_name
596 return self.declarator.analyse(base_type, env, nonempty = nonempty)
597 else:
598 return self.name_declarator, self.type
600 def annotate(self, code):
601 if self.default:
602 self.default.annotate(code)
605 class CBaseTypeNode(Node):
606 # Abstract base class for C base type nodes.
607 #
608 # Processing during analyse_declarations phase:
609 #
610 # analyse
611 # Returns the type.
613 pass
615 class CAnalysedBaseTypeNode(Node):
616 # type type
618 child_attrs = []
620 def analyse(self, env, could_be_name = False):
621 return self.type
623 class CSimpleBaseTypeNode(CBaseTypeNode):
624 # name string
625 # module_path [string] Qualifying name components
626 # is_basic_c_type boolean
627 # signed boolean
628 # longness integer
629 # is_self_arg boolean Is self argument of C method
631 child_attrs = []
632 arg_name = None # in case the argument name was interpreted as a type
634 def analyse(self, env, could_be_name = False):
635 # Return type descriptor.
636 #print "CSimpleBaseTypeNode.analyse: is_self_arg =", self.is_self_arg ###
637 type = None
638 if self.is_basic_c_type:
639 type = PyrexTypes.simple_c_type(self.signed, self.longness, self.name)
640 if not type:
641 error(self.pos, "Unrecognised type modifier combination")
642 elif self.name == "object" and not self.module_path:
643 type = py_object_type
644 elif self.name is None:
645 if self.is_self_arg and env.is_c_class_scope:
646 #print "CSimpleBaseTypeNode.analyse: defaulting to parent type" ###
647 type = env.parent_type
648 else:
649 type = py_object_type
650 else:
651 if self.module_path:
652 scope = env.find_imported_module(self.module_path, self.pos)
653 else:
654 scope = env
655 if scope:
656 if scope.is_c_class_scope:
657 scope = scope.global_scope()
658 entry = scope.lookup(self.name)
659 if entry and entry.is_type:
660 type = entry.type
661 elif could_be_name:
662 if self.is_self_arg and env.is_c_class_scope:
663 type = env.parent_type
664 else:
665 type = py_object_type
666 self.arg_name = self.name
667 else:
668 error(self.pos, "'%s' is not a type identifier" % self.name)
669 if type:
670 return type
671 else:
672 return PyrexTypes.error_type
674 class CBufferAccessTypeNode(CBaseTypeNode):
675 # After parsing:
676 # positional_args [ExprNode] List of positional arguments
677 # keyword_args DictNode Keyword arguments
678 # base_type_node CBaseTypeNode
680 # After analysis:
681 # type PyrexType.BufferType ...containing the right options
684 child_attrs = ["base_type_node", "positional_args",
685 "keyword_args", "dtype_node"]
687 dtype_node = None
689 def analyse(self, env, could_be_name = False):
690 base_type = self.base_type_node.analyse(env)
691 if base_type.is_error: return base_type
692 import Buffer
694 options = Buffer.analyse_buffer_options(
695 self.pos,
696 env,
697 self.positional_args,
698 self.keyword_args,
699 base_type.buffer_defaults)
701 self.type = PyrexTypes.BufferType(base_type, **options)
702 return self.type
704 class CComplexBaseTypeNode(CBaseTypeNode):
705 # base_type CBaseTypeNode
706 # declarator CDeclaratorNode
708 child_attrs = ["base_type", "declarator"]
710 def analyse(self, env, could_be_name = False):
711 base = self.base_type.analyse(env, could_be_name)
712 _, type = self.declarator.analyse(base, env)
713 return type
716 class CVarDefNode(StatNode):
717 # C variable definition or forward/extern function declaration.
718 #
719 # visibility 'private' or 'public' or 'extern'
720 # base_type CBaseTypeNode
721 # declarators [CDeclaratorNode]
722 # in_pxd boolean
723 # api boolean
724 # need_properties [entry]
725 # pxd_locals [CVarDefNode] (used for functions declared in pxd)
727 child_attrs = ["base_type", "declarators"]
728 need_properties = ()
729 pxd_locals = []
731 def analyse_declarations(self, env, dest_scope = None):
732 if not dest_scope:
733 dest_scope = env
734 self.dest_scope = dest_scope
735 base_type = self.base_type.analyse(env)
736 if (dest_scope.is_c_class_scope
737 and self.visibility == 'public'
738 and base_type.is_pyobject
739 and (base_type.is_builtin_type or base_type.is_extension_type)):
740 self.need_properties = []
741 need_property = True
742 visibility = 'private'
743 else:
744 need_property = False
745 visibility = self.visibility
747 for declarator in self.declarators:
748 name_declarator, type = declarator.analyse(base_type, env)
749 if not type.is_complete():
750 if not (self.visibility == 'extern' and type.is_array):
751 error(declarator.pos,
752 "Variable type '%s' is incomplete" % type)
753 if self.visibility == 'extern' and type.is_pyobject:
754 error(declarator.pos,
755 "Python object cannot be declared extern")
756 name = name_declarator.name
757 cname = name_declarator.cname
758 if name == '':
759 error(declarator.pos, "Missing name in declaration.")
760 return
761 if type.is_cfunction:
762 entry = dest_scope.declare_cfunction(name, type, declarator.pos,
763 cname = cname, visibility = self.visibility, in_pxd = self.in_pxd,
764 api = self.api)
765 if entry is not None:
766 entry.pxd_locals = self.pxd_locals
767 else:
768 if self.in_pxd and self.visibility != 'extern':
769 error(self.pos,
770 "Only 'extern' C variable declaration allowed in .pxd file")
771 entry = dest_scope.declare_var(name, type, declarator.pos,
772 cname = cname, visibility = visibility, is_cdef = 1)
773 if need_property:
774 self.need_properties.append(entry)
775 entry.needs_property = 1
778 class CStructOrUnionDefNode(StatNode):
779 # name string
780 # cname string or None
781 # kind "struct" or "union"
782 # typedef_flag boolean
783 # visibility "public" or "private"
784 # in_pxd boolean
785 # attributes [CVarDefNode] or None
786 # entry Entry
788 child_attrs = ["attributes"]
790 def analyse_declarations(self, env):
791 scope = None
792 if self.attributes is not None:
793 scope = StructOrUnionScope(self.name)
794 self.entry = env.declare_struct_or_union(
795 self.name, self.kind, scope, self.typedef_flag, self.pos,
796 self.cname, visibility = self.visibility)
797 if self.attributes is not None:
798 if self.in_pxd and not env.in_cinclude:
799 self.entry.defined_in_pxd = 1
800 for attr in self.attributes:
801 attr.analyse_declarations(env, scope)
802 if self.visibility != 'extern':
803 need_typedef_indirection = False
804 for attr in scope.var_entries:
805 type = attr.type
806 while type.is_array:
807 type = type.base_type
808 if type == self.entry.type:
809 error(attr.pos, "Struct cannot contain itself as a member.")
810 if self.typedef_flag:
811 while type.is_ptr:
812 type = type.base_type
813 if type == self.entry.type:
814 need_typedef_indirection = True
815 if need_typedef_indirection:
816 # C can't handle typedef structs that refer to themselves.
817 struct_entry = self.entry
818 cname = env.new_const_cname()
819 self.entry = env.declare_typedef(self.name, struct_entry.type, self.pos, cname = self.cname, visibility='ignore')
820 struct_entry.type.typedef_flag = False
821 struct_entry.cname = struct_entry.type.cname = env.new_const_cname()
823 def analyse_expressions(self, env):
824 pass
826 def generate_execution_code(self, code):
827 pass
830 class CEnumDefNode(StatNode):
831 # name string or None
832 # cname string or None
833 # items [CEnumDefItemNode]
834 # typedef_flag boolean
835 # visibility "public" or "private"
836 # in_pxd boolean
837 # entry Entry
839 child_attrs = ["items"]
841 def analyse_declarations(self, env):
842 self.entry = env.declare_enum(self.name, self.pos,
843 cname = self.cname, typedef_flag = self.typedef_flag,
844 visibility = self.visibility)
845 if self.items is not None:
846 if self.in_pxd and not env.in_cinclude:
847 self.entry.defined_in_pxd = 1
848 for item in self.items:
849 item.analyse_declarations(env, self.entry)
851 def analyse_expressions(self, env):
852 if self.visibility == 'public':
853 self.temp = env.allocate_temp_pyobject()
854 env.release_temp(self.temp)
856 def generate_execution_code(self, code):
857 if self.visibility == 'public':
858 for item in self.entry.enum_values:
859 code.putln("%s = PyInt_FromLong(%s); %s" % (
860 self.temp,
861 item.cname,
862 code.error_goto_if_null(self.temp, item.pos)))
863 code.putln('if (PyObject_SetAttrString(%s, "%s", %s) < 0) %s' % (
864 Naming.module_cname,
865 item.name,
866 self.temp,
867 code.error_goto(item.pos)))
868 code.putln("%s = 0;" % self.temp)
871 class CEnumDefItemNode(StatNode):
872 # name string
873 # cname string or None
874 # value ExprNode or None
876 child_attrs = ["value"]
878 def analyse_declarations(self, env, enum_entry):
879 if self.value:
880 self.value.analyse_const_expression(env)
881 if not self.value.type.is_int:
882 self.value = self.value.coerce_to(PyrexTypes.c_int_type, env)
883 self.value.analyse_const_expression(env)
884 value = self.value.result()
885 else:
886 value = self.name
887 entry = env.declare_const(self.name, enum_entry.type,
888 value, self.pos, cname = self.cname, visibility = enum_entry.visibility)
889 enum_entry.enum_values.append(entry)
892 class CTypeDefNode(StatNode):
893 # base_type CBaseTypeNode
894 # declarator CDeclaratorNode
895 # visibility "public" or "private"
896 # in_pxd boolean
898 child_attrs = ["base_type", "declarator"]
900 def analyse_declarations(self, env):
901 base = self.base_type.analyse(env)
902 name_declarator, type = self.declarator.analyse(base, env)
903 name = name_declarator.name
904 cname = name_declarator.cname
905 entry = env.declare_typedef(name, type, self.pos,
906 cname = cname, visibility = self.visibility)
907 if self.in_pxd and not env.in_cinclude:
908 entry.defined_in_pxd = 1
910 def analyse_expressions(self, env):
911 pass
912 def generate_execution_code(self, code):
913 pass
916 class FuncDefNode(StatNode, BlockNode):
917 # Base class for function definition nodes.
918 #
919 # return_type PyrexType
920 # #filename string C name of filename string const
921 # entry Symtab.Entry
922 # needs_closure boolean Whether or not this function has inner functions/classes/yield
923 # pxd_locals [CVarDefNode] locals defined in the pxd
925 py_func = None
926 assmt = None
927 needs_closure = False
928 pxd_locals = []
930 def analyse_default_values(self, env):
931 genv = env.global_scope()
932 for arg in self.args:
933 if arg.default:
934 if arg.is_generic:
935 if not hasattr(arg, 'default_entry'):
936 arg.default.analyse_types(env)
937 arg.default = arg.default.coerce_to(arg.type, genv)
938 if arg.default.is_literal:
939 arg.default_entry = arg.default
940 arg.default_result_code = arg.default.calculate_result_code()
941 if arg.default.type != arg.type and not arg.type.is_int:
942 arg.default_result_code = arg.type.cast_code(arg.default_result_code)
943 else:
944 arg.default.allocate_temps(genv)
945 arg.default_entry = genv.add_default_value(arg.type)
946 arg.default_entry.used = 1
947 arg.default_result_code = arg.default_entry.cname
948 else:
949 error(arg.pos,
950 "This argument cannot have a default value")
951 arg.default = None
953 def need_gil_acquisition(self, lenv):
954 return 0
956 def create_local_scope(self, env):
957 genv = env
958 while env.is_py_class_scope or env.is_c_class_scope:
959 env = env.outer_scope
960 if self.needs_closure:
961 lenv = GeneratorLocalScope(name = self.entry.name, outer_scope = genv)
962 else:
963 lenv = LocalScope(name = self.entry.name, outer_scope = genv)
964 lenv.return_type = self.return_type
965 type = self.entry.type
966 if type.is_cfunction:
967 lenv.nogil = type.nogil and not type.with_gil
968 self.local_scope = lenv
969 return lenv
971 def generate_function_definitions(self, env, code):
972 import Buffer
974 lenv = self.local_scope
976 is_getbuffer_slot = (self.entry.name == "__getbuffer__" and
977 self.entry.scope.is_c_class_scope)
979 # Generate C code for header and body of function
980 code.enter_cfunc_scope()
981 code.return_from_error_cleanup_label = code.new_label()
983 # ----- Top-level constants used by this function
984 code.mark_pos(self.pos)
985 self.generate_interned_num_decls(lenv, code)
986 self.generate_interned_string_decls(lenv, code)
987 self.generate_py_string_decls(lenv, code)
988 self.generate_cached_builtins_decls(lenv, code)
989 #code.putln("")
990 #code.put_var_declarations(lenv.const_entries, static = 1)
991 self.generate_const_definitions(lenv, code)
992 # ----- Function header
993 code.putln("")
994 if self.py_func:
995 self.py_func.generate_function_header(code,
996 with_pymethdef = env.is_py_class_scope,
997 proto_only=True)
998 self.generate_function_header(code,
999 with_pymethdef = env.is_py_class_scope)
1000 # ----- Local variable declarations
1001 lenv.mangle_closure_cnames(Naming.cur_scope_cname)
1002 self.generate_argument_declarations(lenv, code)
1003 if self.needs_closure:
1004 code.putln("/* TODO: declare and create scope object */")
1005 code.put_var_declarations(lenv.var_entries)
1006 init = ""
1007 if not self.return_type.is_void:
1008 code.putln(
1009 "%s%s;" %
1010 (self.return_type.declaration_code(
1011 Naming.retval_cname),
1012 init))
1013 tempvardecl_code = code.insertion_point()
1014 self.generate_keyword_list(code)
1015 # ----- Extern library function declarations
1016 lenv.generate_library_function_declarations(code)
1017 # ----- GIL acquisition
1018 acquire_gil = self.need_gil_acquisition(lenv)
1019 if acquire_gil:
1020 code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
1021 # ----- Automatic lead-ins for certain special functions
1022 if is_getbuffer_slot:
1023 self.getbuffer_init(code)
1024 # ----- Fetch arguments
1025 self.generate_argument_parsing_code(env, code)
1026 # If an argument is assigned to in the body, we must
1027 # incref it to properly keep track of refcounts.
1028 for entry in lenv.arg_entries:
1029 if entry.type.is_pyobject and lenv.control_flow.get_state((entry.name, 'source')) != 'arg':
1030 code.put_var_incref(entry)
1031 # ----- Initialise local variables
1032 for entry in lenv.var_entries:
1033 if entry.type.is_pyobject and entry.init_to_none and entry.used:
1034 code.put_init_var_to_py_none(entry)
1035 # ----- Initialise local buffer auxiliary variables
1036 for entry in lenv.var_entries + lenv.arg_entries:
1037 if entry.type.is_buffer and entry.buffer_aux.buffer_info_var.used:
1038 code.putln("%s.buf = NULL;" % entry.buffer_aux.buffer_info_var.cname)
1039 # ----- Check and convert arguments
1040 self.generate_argument_type_tests(code)
1041 # ----- Acquire buffer arguments
1042 for entry in lenv.arg_entries:
1043 if entry.type.is_buffer:
1044 Buffer.put_acquire_arg_buffer(entry, code, self.pos)
1045 # ----- Function body
1046 self.body.generate_execution_code(code)
1047 # ----- Default return value
1048 code.putln("")
1049 if self.return_type.is_pyobject:
1050 #if self.return_type.is_extension_type:
1051 # lhs = "(PyObject *)%s" % Naming.retval_cname
1052 #else:
1053 lhs = Naming.retval_cname
1054 code.put_init_to_py_none(lhs, self.return_type)
1055 else:
1056 val = self.return_type.default_value
1057 if val:
1058 code.putln("%s = %s;" % (Naming.retval_cname, val))
1059 # ----- Error cleanup
1060 if code.error_label in code.labels_used:
1061 code.put_goto(code.return_label)
1062 code.put_label(code.error_label)
1063 # cleanup temps the old way
1064 code.put_var_xdecrefs(lenv.temp_entries)
1065 # cleanup temps the new way
1066 for cname, type in code.funcstate.all_managed_temps():
1067 code.put_xdecref(cname, type)
1069 # Clean up buffers -- this calls a Python function
1070 # so need to save and restore error state
1071 buffers_present = len(lenv.buffer_entries) > 0
1072 if buffers_present:
1073 code.globalstate.use_utility_code(restore_exception_utility_code)
1074 code.putln("{ PyObject *__pyx_type, *__pyx_value, *__pyx_tb;")
1075 code.putln("__Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);")
1076 for entry in lenv.buffer_entries:
1077 code.putln("%s;" % Buffer.get_release_buffer_code(entry))
1078 #code.putln("%s = 0;" % entry.cname)
1079 code.putln("__Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}")
1081 err_val = self.error_value()
1082 exc_check = self.caller_will_check_exceptions()
1083 if err_val is not None or exc_check:
1084 code.putln('__Pyx_AddTraceback("%s");' % self.entry.qualified_name)
1085 else:
1086 warning(self.entry.pos, "Unraisable exception in function '%s'." \
1087 % self.entry.qualified_name, 0)
1088 code.putln(
1089 '__Pyx_WriteUnraisable("%s");' %
1090 self.entry.qualified_name)
1091 env.use_utility_code(unraisable_exception_utility_code)
1092 env.use_utility_code(restore_exception_utility_code)
1093 default_retval = self.return_type.default_value
1094 if err_val is None and default_retval:
1095 err_val = default_retval
1096 if err_val is not None:
1097 code.putln(
1098 "%s = %s;" % (
1099 Naming.retval_cname,
1100 err_val))
1102 if is_getbuffer_slot:
1103 self.getbuffer_error_cleanup(code)
1105 # If we are using the non-error cleanup section we should
1106 # jump past it if we have an error. The if-test below determine
1107 # whether this section is used.
1108 if buffers_present or is_getbuffer_slot:
1109 code.put_goto(code.return_from_error_cleanup_label)
1112 # ----- Non-error return cleanup
1113 # If you add anything here, remember to add a condition to the
1114 # if-test above in the error block (so that it can jump past this
1115 # block).
1116 code.put_label(code.return_label)
1117 for entry in lenv.buffer_entries:
1118 if entry.used:
1119 code.putln("%s;" % Buffer.get_release_buffer_code(entry))
1120 if is_getbuffer_slot:
1121 self.getbuffer_normal_cleanup(code)
1122 # ----- Return cleanup for both error and no-error return
1123 code.put_label(code.return_from_error_cleanup_label)
1124 if not Options.init_local_none:
1125 for entry in lenv.var_entries:
1126 if lenv.control_flow.get_state((entry.name, 'initalized')) is not True:
1127 entry.xdecref_cleanup = 1
1128 code.put_var_decrefs(lenv.var_entries, used_only = 1)
1129 # Decref any increfed args
1130 for entry in lenv.arg_entries:
1131 if entry.type.is_pyobject and lenv.control_flow.get_state((entry.name, 'source')) != 'arg':
1132 code.put_var_decref(entry)
1133 if acquire_gil:
1134 code.putln("PyGILState_Release(_save);")
1135 # code.putln("/* TODO: decref scope object */")
1136 # ----- Return
1137 if not self.return_type.is_void:
1138 code.putln("return %s;" % Naming.retval_cname)
1139 code.putln("}")
1140 # ----- Go back and insert temp variable declarations
1141 tempvardecl_code.put_var_declarations(lenv.temp_entries)
1142 tempvardecl_code.put_temp_declarations(code.funcstate)
1143 # ----- Python version
1144 code.exit_cfunc_scope()
1145 if self.py_func:
1146 self.py_func.generate_function_definitions(env, code)
1147 self.generate_wrapper_functions(code)
1149 def declare_argument(self, env, arg):
1150 if arg.type.is_void:
1151 error(arg.pos, "Invalid use of 'void'")
1152 elif not arg.type.is_complete() and not arg.type.is_array:
1153 error(arg.pos,
1154 "Argument type '%s' is incomplete" % arg.type)
1155 return env.declare_arg(arg.name, arg.type, arg.pos)
1157 def generate_wrapper_functions(self, code):
1158 pass
1160 def generate_execution_code(self, code):
1161 # Evaluate and store argument default values
1162 for arg in self.args:
1163 default = arg.default
1164 if default:
1165 if not default.is_literal:
1166 default.generate_evaluation_code(code)
1167 default.make_owned_reference(code)
1168 code.putln(
1169 "%s = %s;" % (
1170 arg.default_entry.cname,
1171 default.result_as(arg.default_entry.type)))
1172 if default.is_temp and default.type.is_pyobject:
1173 code.putln(
1174 "%s = 0;" %
1175 default.result())
1176 # For Python class methods, create and store function object
1177 if self.assmt:
1178 self.assmt.generate_execution_code(code)
1181 # Special code for the __getbuffer__ function
1183 def getbuffer_init(self, code):
1184 info = self.local_scope.arg_entries[1].cname
1185 # Python 3.0 betas have a bug in memoryview which makes it call
1186 # getbuffer with a NULL parameter. For now we work around this;
1187 # the following line should be removed when this bug is fixed.
1188 code.putln("if (%s == NULL) return 0;" % info)
1189 code.putln("%s->obj = Py_None; Py_INCREF(Py_None);" % info)
1191 def getbuffer_error_cleanup(self, code):
1192 info = self.local_scope.arg_entries[1].cname
1193 code.putln("Py_DECREF(%s->obj); %s->obj = NULL;" %
1194 (info, info))
1196 def getbuffer_normal_cleanup(self, code):
1197 info = self.local_scope.arg_entries[1].cname
1198 code.putln("if (%s->obj == Py_None) { Py_DECREF(Py_None); %s->obj = NULL; }" %
1199 (info, info))
1201 class CFuncDefNode(FuncDefNode):
1202 # C function definition.
1204 # modifiers ['inline']
1205 # visibility 'private' or 'public' or 'extern'
1206 # base_type CBaseTypeNode
1207 # declarator CDeclaratorNode
1208 # body StatListNode
1209 # api boolean
1211 # with_gil boolean Acquire GIL around body
1212 # type CFuncType
1213 # py_func wrapper for calling from Python
1214 # overridable whether or not this is a cpdef function
1215 # inline_in_pxd whether this is an inline function in a pxd file
1217 child_attrs = ["base_type", "declarator", "body", "py_func"]
1219 inline_in_pxd = False
1221 def unqualified_name(self):
1222 return self.entry.name
1224 def analyse_declarations(self, env):
1225 if 'locals' in env.directives:
1226 directive_locals = env.directives['locals']
1227 else:
1228 directive_locals = {}
1229 self.directive_locals = directive_locals
1230 base_type = self.base_type.analyse(env)
1231 # The 2 here is because we need both function and argument names.
1232 name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None))
1233 if not type.is_cfunction:
1234 error(self.pos,
1235 "Suite attached to non-function declaration")
1236 # Remember the actual type according to the function header
1237 # written here, because the type in the symbol table entry
1238 # may be different if we're overriding a C method inherited
1239 # from the base type of an extension type.
1240 self.type = type
1241 type.is_overridable = self.overridable
1242 declarator = self.declarator
1243 while not hasattr(declarator, 'args'):
1244 declarator = declarator.base
1245 self.args = declarator.args
1246 for formal_arg, type_arg in zip(self.args, type.args):
1247 formal_arg.type = type_arg.type
1248 formal_arg.name = type_arg.name
1249 formal_arg.cname = type_arg.cname
1250 name = name_declarator.name
1251 cname = name_declarator.cname
1252 self.entry = env.declare_cfunction(
1253 name, type, self.pos,
1254 cname = cname, visibility = self.visibility,
1255 defining = self.body is not None,
1256 api = self.api, modifiers = self.modifiers)
1257 self.entry.inline_func_in_pxd = self.inline_in_pxd
1258 self.return_type = type.return_type
1260 if self.overridable:
1261 import ExprNodes
1262 py_func_body = self.call_self_node(is_module_scope = env.is_module_scope)
1263 self.py_func = DefNode(pos = self.pos,
1264 name = self.entry.name,
1265 args = self.args,
1266 star_arg = None,
1267 starstar_arg = None,
1268 doc = self.doc,
1269 body = py_func_body,
1270 is_wrapper = 1)
1271 self.py_func.is_module_scope = env.is_module_scope
1272 self.py_func.analyse_declarations(env)
1273 self.entry.as_variable = self.py_func.entry
1274 # Reset scope entry the above cfunction
1275 env.entries[name] = self.entry
1276 self.py_func.interned_attr_cname = env.intern_identifier(
1277 self.py_func.entry.name)
1278 if not env.is_module_scope or Options.lookup_module_cpdef:
1279 self.override = OverrideCheckNode(self.pos, py_func = self.py_func)
1280 self.body = StatListNode(self.pos, stats=[self.override, self.body])
1282 def call_self_node(self, omit_optional_args=0, is_module_scope=0):
1283 import ExprNodes
1284 args = self.type.args
1285 if omit_optional_args:
1286 args = args[:len(args) - self.type.optional_arg_count]
1287 arg_names = [arg.name for arg in args]
1288 if is_module_scope:
1289 cfunc = ExprNodes.NameNode(self.pos, name=self.entry.name)
1290 else:
1291 self_arg = ExprNodes.NameNode(self.pos, name=arg_names[0])
1292 cfunc = ExprNodes.AttributeNode(self.pos, obj=self_arg, attribute=self.entry.name)
1293 skip_dispatch = not is_module_scope or Options.lookup_module_cpdef
1294 c_call = ExprNodes.SimpleCallNode(self.pos, function=cfunc, args=[ExprNodes.NameNode(self.pos, name=n) for n in arg_names[1-is_module_scope:]], wrapper_call=skip_dispatch)
1295 return ReturnStatNode(pos=self.pos, return_type=PyrexTypes.py_object_type, value=c_call)
1297 def declare_arguments(self, env):
1298 for arg in self.type.args:
1299 if not arg.name:
1300 error(arg.pos, "Missing argument name")
1301 self.declare_argument(env, arg)
1303 def need_gil_acquisition(self, lenv):
1304 type = self.type
1305 with_gil = self.type.with_gil
1306 if type.nogil and not with_gil:
1307 if type.return_type.is_pyobject:
1308 error(self.pos,
1309 "Function with Python return type cannot be declared nogil")
1310 for entry in lenv.var_entries + lenv.temp_entries:
1311 if entry.type.is_pyobject:
1312 error(self.pos, "Function declared nogil has Python locals or temporaries")
1313 return with_gil
1315 def analyse_expressions(self, env):
1316 self.analyse_default_values(env)
1317 if self.overridable:
1318 self.py_func.analyse_expressions(env)
1320 def generate_function_header(self, code, with_pymethdef, with_opt_args = 1, with_dispatch = 1, cname = None):
1321 arg_decls = []
1322 type = self.type
1323 visibility = self.entry.visibility
1324 for arg in type.args[:len(type.args)-type.optional_arg_count]:
1325 arg_decls.append(arg.declaration_code())
1326 if with_dispatch and self.overridable:
1327 arg_decls.append(PyrexTypes.c_int_type.declaration_code(Naming.skip_dispatch_cname))
1328 if type.optional_arg_count and with_opt_args:
1329 arg_decls.append(type.op_arg_struct.declaration_code(Naming.optional_args_cname))
1330 if type.has_varargs:
1331 arg_decls.append("...")
1332 if not arg_decls:
1333 arg_decls = ["void"]
1334 if cname is None:
1335 cname = self.entry.func_cname
1336 entity = type.function_header_code(cname, string.join(arg_decls, ", "))
1337 if visibility == 'public':
1338 dll_linkage = "DL_EXPORT"
1339 else:
1340 dll_linkage = None
1341 header = self.return_type.declaration_code(entity,
1342 dll_linkage = dll_linkage)
1343 if visibility == 'extern':
1344 storage_class = "%s " % Naming.extern_c_macro
1345 elif visibility == 'public':
1346 storage_class = ""
1347 else:
1348 storage_class = "static "
1349 code.putln("%s%s %s {" % (
1350 storage_class,
1351 ' '.join(self.modifiers).upper(), # macro forms
1352 header))
1354 def generate_argument_declarations(self, env, code):
1355 for arg in self.args:
1356 if arg.default:
1357 code.putln('%s = %s;' % (arg.type.declaration_code(arg.cname), arg.default_result_code))
1359 def generate_keyword_list(self, code):
1360 pass
1362 def generate_argument_parsing_code(self, env, code):
1363 i = 0
1364 if self.type.optional_arg_count:
1365 code.putln('if (%s) {' % Naming.optional_args_cname)
1366 for arg in self.args:
1367 if arg.default:
1368 code.putln('if (%s->%sn > %s) {' % (Naming.optional_args_cname, Naming.pyrex_prefix, i))
1369 declarator = arg.declarator
1370 while not hasattr(declarator, 'name'):
1371 declarator = declarator.base
1372 code.putln('%s = %s->%s;' % (arg.cname, Naming.optional_args_cname, declarator.name))
1373 i += 1
1374 for _ in range(self.type.optional_arg_count):
1375 code.putln('}')
1376 code.putln('}')
1378 def generate_argument_conversion_code(self, code):
1379 pass
1381 def generate_argument_type_tests(self, code):
1382 # Generate type tests for args whose type in a parent
1383 # class is a supertype of the declared type.
1384 for arg in self.type.args:
1385 if arg.needs_type_test:
1386 self.generate_arg_type_test(arg, code)
1388 def generate_arg_type_test(self, arg, code):
1389 # Generate type test for one argument.
1390 if arg.type.typeobj_is_available():
1391 typeptr_cname = arg.type.typeptr_cname
1392 arg_code = "((PyObject *)%s)" % arg.cname
1393 code.putln(
1394 'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % (
1395 arg_code,
1396 typeptr_cname,
1397 not arg.not_none,
1398 arg.name,
1399 type.is_builtin_type,
1400 code.error_goto(arg.pos)))
1401 else:
1402 error(arg.pos, "Cannot test type of extern C class "
1403 "without type object name specification")
1405 def error_value(self):
1406 if self.return_type.is_pyobject:
1407 return "0"
1408 else:
1409 #return None
1410 return self.entry.type.exception_value
1412 def caller_will_check_exceptions(self):
1413 return self.entry.type.exception_check
1415 def generate_wrapper_functions(self, code):
1416 # If the C signature of a function has changed, we need to generate
1417 # wrappers to put in the slots here.
1418 k = 0
1419 entry = self.entry
1420 func_type = entry.type
1421 while entry.prev_entry is not None:
1422 k += 1
1423 entry = entry.prev_entry
1424 entry.func_cname = "%s%swrap_%s" % (self.entry.func_cname, Naming.pyrex_prefix, k)
1425 code.putln()
1426 self.generate_function_header(code,
1427 0,
1428 with_dispatch = entry.type.is_overridable,
1429 with_opt_args = entry.type.optional_arg_count,
1430 cname = entry.func_cname)
1431 if not self.return_type.is_void:
1432 code.put('return ')
1433 args = self.type.args
1434 arglist = [arg.cname for arg in args[:len(args)-self.type.optional_arg_count]]
1435 if entry.type.is_overridable:
1436 arglist.append(Naming.skip_dispatch_cname)
1437 elif func_type.is_overridable:
1438 arglist.append('0')
1439 if entry.type.optional_arg_count:
1440 arglist.append(Naming.optional_args_cname)
1441 elif func_type.optional_arg_count:
1442 arglist.append('NULL')
1443 code.putln('%s(%s);' % (self.entry.func_cname, ', '.join(arglist)))
1444 code.putln('}')
1447 class PyArgDeclNode(Node):
1448 # Argument which must be a Python object (used
1449 # for * and ** arguments).
1451 # name string
1452 # entry Symtab.Entry
1453 child_attrs = []
1456 class DecoratorNode(Node):
1457 # A decorator
1459 # decorator NameNode or CallNode
1460 child_attrs = ['decorator']
1463 class DefNode(FuncDefNode):
1464 # A Python function definition.
1466 # name string the Python name of the function
1467 # decorators [DecoratorNode] list of decorators
1468 # args [CArgDeclNode] formal arguments
1469 # star_arg PyArgDeclNode or None * argument
1470 # starstar_arg PyArgDeclNode or None ** argument
1471 # doc EncodedString or None
1472 # body StatListNode
1474 # The following subnode is constructed internally
1475 # when the def statement is inside a Python class definition.
1477 # assmt AssignmentNode Function construction/assignment
1479 child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators"]
1481 assmt = None
1482 num_kwonly_args = 0
1483 num_required_kw_args = 0
1484 reqd_kw_flags_cname = "0"
1485 is_wrapper = 0
1486 decorators = None
1487 entry = None
1490 def __init__(self, pos, **kwds):
1491 FuncDefNode.__init__(self, pos, **kwds)
1492 k = rk = r = 0
1493 for arg in self.args:
1494 if arg.kw_only:
1495 k += 1
1496 if not arg.default:
1497 rk += 1
1498 if not arg.default:
1499 r += 1
1500 self.num_kwonly_args = k
1501 self.num_required_kw_args = rk
1502 self.num_required_args = r
1504 def as_cfunction(self, cfunc=None, scope=None):
1505 if self.star_arg:
1506 error(self.star_arg.pos, "cdef function cannot have star argument")
1507 if self.starstar_arg:
1508 error(self.starstar_arg.pos, "cdef function cannot have starstar argument")
1509 if cfunc is None:
1510 cfunc_args = []
1511 for formal_arg in self.args:
1512 name_declarator, type = formal_arg.analyse(scope, nonempty=1)
1513 cfunc_args.append(PyrexTypes.CFuncTypeArg(name = name_declarator.name,
1514 cname = None,
1515 type = py_object_type,
1516 pos = formal_arg.pos))
1517 cfunc_type = PyrexTypes.CFuncType(return_type = py_object_type,
1518 args = cfunc_args,
1519 has_varargs = False,
1520 exception_value = None,
1521 exception_check = False,
1522 nogil = False,
1523 with_gil = False,
1524 is_overridable = True)
1525 cfunc = CVarDefNode(self.pos, type=cfunc_type, pxd_locals=[])
1526 else:
1527 cfunc_type = cfunc.type
1528 if len(self.args) != len(cfunc_type.args) or cfunc_type.has_varargs:
1529 error(self.pos, "wrong number of arguments")
1530 error(declarator.pos, "previous declaration here")
1531 for formal_arg, type_arg in zip(self.args, cfunc_type.args):
1532 name_declarator, type = formal_arg.analyse(cfunc.scope, nonempty=1)
1533 if type is None or type is PyrexTypes.py_object_type or formal_arg.is_self:
1534 formal_arg.type = type_arg.type
1535 formal_arg.name_declarator = name_declarator
1536 import ExprNodes
1537 if cfunc_type.exception_value is None:
1538 exception_value = None
1539 else:
1540 exception_value = ExprNodes.ConstNode(self.pos, value=cfunc_type.exception_value, type=cfunc_type.return_type)
1541 declarator = CFuncDeclaratorNode(self.pos,
1542 base = CNameDeclaratorNode(self.pos, name=self.name, cname=None),
1543 args = self.args,
1544 has_varargs = False,
1545 exception_check = cfunc_type.exception_check,
1546 exception_value = exception_value,
1547 with_gil = cfunc_type.with_gil,
1548 nogil = cfunc_type.nogil)
1549 return CFuncDefNode(self.pos,
1550 modifiers = [],
1551 base_type = CAnalysedBaseTypeNode(self.pos, type=cfunc_type.return_type),
1552 declarator = declarator,
1553 body = self.body,
1554 doc = self.doc,
1555 overridable = cfunc_type.is_overridable,
1556 type = cfunc_type,
1557 with_gil = cfunc_type.with_gil,
1558 nogil = cfunc_type.nogil,
1559 visibility = 'private',
1560 api = False,
1561 pxd_locals = cfunc.pxd_locals)
1563 def analyse_declarations(self, env):
1564 if 'locals' in env.directives:
1565 directive_locals = env.directives['locals']
1566 else:
1567 directive_locals = {}
1568 self.directive_locals = directive_locals
1569 for arg in self.args:
1570 if hasattr(arg, 'name'):
1571 type = arg.type
1572 name_declarator = None
1573 else:
1574 base_type = arg.base_type.analyse(env)
1575 name_declarator, type = \
1576 arg.declarator.analyse(base_type, env)
1577 arg.name = name_declarator.name
1578 if arg.name in directive_locals:
1579 type_node = directive_locals[arg.name]
1580 other_type = type_node.analyse_as_type(env)
1581 if other_type is None:
1582 error(type_node.pos, "Not a type")
1583 elif (type is not PyrexTypes.py_object_type
1584 and not type.same_as(other_type)):
1585 error(arg.base_type.pos, "Signature does not agree with previous declaration")
1586 error(type_node.pos, "Previous declaration here")
1587 else:
1588 type = other_type
1589 if name_declarator and name_declarator.cname:
1590 error(self.pos,
1591 "Python function argument cannot have C name specification")
1592 arg.type = type.as_argument_type()
1593 arg.hdr_type = None
1594 arg.needs_conversion = 0
1595 arg.needs_type_test = 0
1596 arg.is_generic = 1
1597 if arg.not_none and not arg.type.is_extension_type:
1598 error(self.pos,
1599 "Only extension type arguments can have 'not None'")
1600 self.declare_pyfunction(env)
1601 self.analyse_signature(env)
1602 self.return_type = self.entry.signature.return_type()
1604 def analyse_signature(self, env):
1605 any_type_tests_needed = 0
1606 # Use the simpler calling signature for zero- and one-argument functions.
1607 if not self.entry.is_special and not self.star_arg and not self.starstar_arg:
1608 if self.entry.signature is TypeSlots.pyfunction_signature and Options.optimize_simple_methods:
1609 if len(self.args) == 0:
1610 self.entry.signature = TypeSlots.pyfunction_noargs
1611 elif len(self.args) == 1:
1612 if self.args[0].default is None and not self.args[0].kw_only:
1613 self.entry.signature = TypeSlots.pyfunction_onearg
1614 elif self.entry.signature is TypeSlots.pymethod_signature:
1615 if len(self.args) == 1:
1616 self.entry.signature = TypeSlots.unaryfunc
1617 elif len(self.args) == 2:
1618 if self.args[1].default is None and not self.args[1].kw_only:
1619 self.entry.signature = TypeSlots.ibinaryfunc
1620 elif self.entry.is_special:
1621 self.entry.trivial_signature = len(self.args) == 1 and not (self.star_arg or self.starstar_arg)
1622 sig = self.entry.signature
1623 nfixed = sig.num_fixed_args()
1624 for i in range(nfixed):
1625 if i < len(self.args):
1626 arg = self.args[i]
1627 arg.is_generic = 0
1628 if sig.is_self_arg(i):
1629 arg.is_self_arg = 1
1630 arg.hdr_type = arg.type = env.parent_type
1631 arg.needs_conversion = 0
1632 else:
1633 arg.hdr_type = sig.fixed_arg_type(i)
1634 if not arg.type.same_as(arg.hdr_type):
1635 if arg.hdr_type.is_pyobject and arg.type.is_pyobject:
1636 arg.needs_type_test = 1
1637 any_type_tests_needed = 1
1638 else:
1639 arg.needs_conversion = 1
1640 if arg.needs_conversion:
1641 arg.hdr_cname = Naming.arg_prefix + arg.name
1642 else:
1643 arg.hdr_cname = Naming.var_prefix + arg.name
1644 else:
1645 self.bad_signature()
1646 return
1647 if nfixed < len(self.args):
1648 if not sig.has_generic_args:
1649 self.bad_signature()
1650 for arg in self.args:
1651 if arg.is_generic and \
1652 (arg.type.is_extension_type or arg.type.is_builtin_type):
1653 arg.needs_type_test = 1
1654 any_type_tests_needed = 1
1655 elif arg.type is PyrexTypes.c_py_ssize_t_type:
1656 # Want to use __index__ rather than __int__ method
1657 # that PyArg_ParseTupleAndKeywords calls
1658 arg.needs_conversion = 1
1659 arg.hdr_type = PyrexTypes.py_object_type
1660 arg.hdr_cname = Naming.arg_prefix + arg.name
1661 if any_type_tests_needed:
1662 env.use_utility_code(arg_type_test_utility_code)
1664 def bad_signature(self):
1665 sig = self.entry.signature
1666 expected_str = "%d" % sig.num_fixed_args()
1667 if sig.has_generic_args:
1668 expected_str = expected_str + " or more"
1669 name = self.name
1670 if name.startswith("__") and name.endswith("__"):
1671 desc = "Special method"
1672 else:
1673 desc = "Method"
1674 error(self.pos,
1675 "%s %s has wrong number of arguments "
1676 "(%d declared, %s expected)" % (
1677 desc, self.name, len(self.args), expected_str))
1679 def signature_has_nongeneric_args(self):
1680 argcount = len(self.args)
1681 if argcount == 0 or (argcount == 1 and self.args[0].is_self_arg):
1682 return 0
1683 return 1
1685 def signature_has_generic_args(self):
1686 return self.entry.signature.has_generic_args
1688 def declare_pyfunction(self, env):
1689 #print "DefNode.declare_pyfunction:", self.name, "in", env ###
1690 name = self.name
1691 entry = env.lookup_here(self.name)
1692 if entry and entry.type.is_cfunction and not self.is_wrapper:
1693 warning(self.pos, "Overriding cdef method with def method.", 5)
1694 entry = env.declare_pyfunction(self.name, self.pos)
1695 self.entry = entry
1696 prefix = env.scope_prefix
1697 entry.func_cname = \
1698 Naming.pyfunc_prefix + prefix + name
1699 entry.pymethdef_cname = \
1700 Naming.pymethdef_prefix + prefix + name
1701 if Options.docstrings:
1702 entry.doc = embed_position(self.pos, self.doc)
1703 entry.doc_cname = \
1704 Naming.funcdoc_prefix + prefix + name
1705 else:
1706 entry.doc = None
1708 def declare_arguments(self, env):
1709 for arg in self.args:
1710 if not arg.name:
1711 error(arg.pos, "Missing argument name")
1712 if arg.needs_conversion:
1713 arg.entry = env.declare_var(arg.name, arg.type, arg.pos)
1714 env.control_flow.set_state((), (arg.name, 'source'), 'arg')
1715 env.control_flow.set_state((), (arg.name, 'initalized'), True)
1716 if arg.type.is_pyobject:
1717 arg.entry.init = "0"
1718 arg.entry.init_to_none = 0
1719 else:
1720 arg.entry = self.declare_argument(env, arg)
1721 arg.entry.used = 1
1722 arg.entry.is_self_arg = arg.is_self_arg
1723 if not arg.is_self_arg:
1724 arg.name_entry = env.get_string_const(
1725 arg.name, identifier = True)
1726 env.add_py_string(arg.name_entry, identifier = True)
1727 if arg.hdr_type:
1728 if arg.is_self_arg or \
1729 (arg.type.is_extension_type and not arg.hdr_type.is_extension_type):
1730 arg.entry.is_declared_generic = 1
1731 self.declare_python_arg(env, self.star_arg)
1732 self.declare_python_arg(env, self.starstar_arg)
1734 def declare_python_arg(self, env, arg):
1735 if arg:
1736 entry = env.declare_var(arg.name,
1737 PyrexTypes.py_object_type, arg.pos)
1738 entry.used = 1
1739 entry.init = "0"
1740 entry.init_to_none = 0
1741 entry.xdecref_cleanup = 1
1742 arg.entry = entry
1743 env.control_flow.set_state((), (arg.name, 'initalized'), True)
1745 def analyse_expressions(self, env):
1746 self.analyse_default_values(env)
1747 if env.is_py_class_scope:
1748 self.synthesize_assignment_node(env)
1750 def synthesize_assignment_node(self, env):
1751 import ExprNodes
1752 self.assmt = SingleAssignmentNode(self.pos,
1753 lhs = ExprNodes.NameNode(self.pos, name = self.name),
1754 rhs = ExprNodes.UnboundMethodNode(self.pos,
1755 class_cname = env.class_obj_cname,
1756 function = ExprNodes.PyCFunctionNode(self.pos,
1757 pymethdef_cname = self.entry.pymethdef_cname)))
1758 self.assmt.analyse_declarations(env)
1759 self.assmt.analyse_expressions(env)
1761 def generate_function_header(self, code, with_pymethdef, proto_only=0):
1762 arg_code_list = []
1763 sig = self.entry.signature
1764 if sig.has_dummy_arg:
1765 arg_code_list.append(
1766 "PyObject *%s" % Naming.self_cname)
1767 for arg in self.args:
1768 if not arg.is_generic:
1769 if arg.is_self_arg:
1770 arg_code_list.append("PyObject *%s" % arg.hdr_cname)
1771 else:
1772 arg_code_list.append(
1773 arg.hdr_type.declaration_code(arg.hdr_cname))
1774 if not self.entry.is_special and sig.method_flags() == [TypeSlots.method_noargs]:
1775 arg_code_list.append("PyObject *unused")
1776 if sig.has_generic_args:
1777 arg_code_list.append(
1778 "PyObject *%s, PyObject *%s"
1779 % (Naming.args_cname, Naming.kwds_cname))
1780 arg_code = ", ".join(arg_code_list)
1781 dc = self.return_type.declaration_code(self.entry.func_cname)
1782 header = "static %s(%s)" % (dc, arg_code)
1783 code.putln("%s; /*proto*/" % header)
1784 if proto_only:
1785 return
1786 if self.entry.doc and Options.docstrings:
1787 docstr = self.entry.doc
1788 if not isinstance(docstr, str):
1789 docstr = docstr.utf8encode()
1790 code.putln(
1791 'static char %s[] = "%s";' % (
1792 self.entry.doc_cname,
1793 split_docstring(escape_byte_string(docstr))))
1794 if with_pymethdef:
1795 code.put(
1796 "static PyMethodDef %s = " %
1797 self.entry.pymethdef_cname)
1798 code.put_pymethoddef(self.entry, ";")
1799 code.putln("%s {" % header)
1801 def generate_argument_declarations(self, env, code):
1802 for arg in self.args:
1803 if arg.is_generic: # or arg.needs_conversion:
1804 if arg.needs_conversion:
1805 code.putln("PyObject *%s = 0;" % arg.hdr_cname)
1806 else:
1807 code.put_var_declaration(arg.entry)
1809 def generate_keyword_list(self, code):
1810 if self.signature_has_generic_args() and \
1811 self.signature_has_nongeneric_args():
1812 code.put(
1813 "static PyObject **%s[] = {" %
1814 Naming.pykwdlist_cname)
1815 for arg in self.args:
1816 if arg.is_generic:
1817 code.put('&%s,' % arg.name_entry.pystring_cname)
1818 code.putln("0};")
1820 def generate_argument_parsing_code(self, env, code):
1821 # Generate PyArg_ParseTuple call for generic
1822 # arguments, if any.
1823 if self.entry.signature.has_dummy_arg:
1824 # get rid of unused argument warning
1825 code.putln("%s = %s;" % (Naming.self_cname, Naming.self_cname))
1827 old_error_label = code.new_error_label()
1828 our_error_label = code.error_label
1829 end_label = code.new_label("argument_unpacking_done")
1831 has_kwonly_args = self.num_kwonly_args > 0
1832 has_star_or_kw_args = self.star_arg is not None \
1833 or self.starstar_arg is not None or has_kwonly_args
1835 if not self.signature_has_generic_args():
1836 if has_star_or_kw_args:
1837 error(self.pos, "This method cannot have * or keyword arguments")
1838 self.generate_argument_conversion_code(code)
1840 elif not self.signature_has_nongeneric_args():
1841 # func(*args) or func(**kw) or func(*args, **kw)
1842 self.generate_stararg_copy_code(code)
1844 else:
1845 positional_args = []
1846 kw_only_args = []
1847 default_seen = 0
1848 for arg in self.args:
1849 arg_entry = arg.entry
1850 if arg.is_generic:
1851 if arg.default:
1852 code.putln(
1853 "%s = %s;" % (
1854 arg_entry.cname,
1855 arg.default_result_code))
1856 default_seen = 1
1857 if not arg.is_self_arg:
1858 if arg.kw_only:
1859 kw_only_args.append(arg)
1860 else:
1861 positional_args.append(arg)
1862 elif arg.kw_only:
1863 kw_only_args.append(arg)
1864 default_seen = 1
1865 elif default_seen:
1866 error(arg.pos, "Non-default argument following default argument")
1867 elif not arg.is_self_arg:
1868 positional_args.append(arg)
1869 if arg.needs_conversion:
1870 format = arg.hdr_type.parsetuple_format
1871 else:
1872 format = arg_entry.type.parsetuple_format
1873 if not format:
1874 error(arg.pos,
1875 "Cannot convert Python object argument to type '%s' (when parsing input arguments)"
1876 % arg.type)
1878 self.generate_tuple_and_keyword_parsing_code(
1879 positional_args, kw_only_args, end_label, code)
1881 code.error_label = old_error_label
1882 if code.label_used(our_error_label):
1883 if not code.label_used(end_label):
1884 code.put_goto(end_label)
1885 code.put_label(our_error_label)
1886 if has_star_or_kw_args:
1887 self.generate_arg_decref(self.star_arg, code)
1888 if self.starstar_arg:
1889 if self.starstar_arg.entry.xdecref_cleanup:
1890 code.put_var_xdecref(self.starstar_arg.entry)
1891 else:
1892 code.put_var_decref(self.starstar_arg.entry)
1893 code.putln('__Pyx_AddTraceback("%s");' % self.entry.qualified_name)
1894 code.putln("return %s;" % self.error_value())
1895 if code.label_used(end_label):
1896 code.put_label(end_label)
1898 def generate_arg_assignment(self, arg, item, code):
1899 if arg.type.is_pyobject:
1900 if arg.is_generic:
1901 item = PyrexTypes.typecast(arg.type, PyrexTypes.py_object_type, item)
1902 code.putln("%s = %s;" % (arg.entry.cname, item))
1903 else:
1904 func = arg.type.from_py_function
1905 if func:
1906 code.putln("%s = %s(%s); %s" % (
1907 arg.entry.cname,
1908 func,
1909 item,
1910 code.error_goto_if(arg.type.error_condition(arg.entry.cname), arg.pos)))
1911 else:
1912 error(arg.pos, "Cannot convert Python object argument to type '%s'" % arg.type)
1914 def generate_arg_xdecref(self, arg, code):
1915 if arg:
1916 code.put_var_xdecref(arg.entry)
1918 def generate_arg_decref(self, arg, code):
1919 if arg:
1920 code.put_var_decref(arg.entry)
1922 def generate_stararg_copy_code(self, code):
1923 if not self.star_arg:
1924 code.globalstate.use_utility_code(raise_argtuple_invalid_utility_code)
1925 code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > 0)) {" %
1926 Naming.args_cname)
1927 code.put('__Pyx_RaiseArgtupleInvalid("%s", 1, 0, 0, PyTuple_GET_SIZE(%s)); return %s;' % (
1928 self.name.utf8encode(), Naming.args_cname, self.error_value()))
1929 code.putln("}")
1931 code.globalstate.use_utility_code(keyword_string_check_utility_code)
1933 if self.starstar_arg:
1934 if self.star_arg:
1935 kwarg_check = "unlikely(%s)" % Naming.kwds_cname
1936 else:
1937 kwarg_check = "%s" % Naming.kwds_cname
1938 else:
1939 kwarg_check = "unlikely(%s) && unlikely(PyDict_Size(%s) > 0)" % (
1940 Naming.kwds_cname, Naming.kwds_cname)
1941 code.putln(
1942 "if (%s && unlikely(!__Pyx_CheckKeywordStrings(%s, \"%s\", %d))) return %s;" % (
1943 kwarg_check, Naming.kwds_cname, self.name,
1944 bool(self.starstar_arg), self.error_value()))
1946 if self.starstar_arg:
1947 code.putln("%s = (%s) ? PyDict_Copy(%s) : PyDict_New();" % (
1948 self.starstar_arg.entry.cname,
1949 Naming.kwds_cname,
1950 Naming.kwds_cname))
1951 code.putln("if (unlikely(!%s)) return %s;" % (
1952 self.starstar_arg.entry.cname, self.error_value()))
1953 self.starstar_arg.entry.xdecref_cleanup = 0
1955 if self.star_arg:
1956 code.put_incref(Naming.args_cname, py_object_type)
1957 code.putln("%s = %s;" % (
1958 self.star_arg.entry.cname,
1959 Naming.args_cname))
1960 self.star_arg.entry.xdecref_cleanup = 0
1962 def generate_tuple_and_keyword_parsing_code(self, positional_args,
1963 kw_only_args, success_label, code):
1964 argtuple_error_label = code.new_label("argtuple_error")
1966 min_positional_args = self.num_required_args - self.num_required_kw_args
1967 if len(self.args) > 0 and self.args[0].is_self_arg:
1968 min_positional_args -= 1
1969 max_positional_args = len(positional_args)
1970 has_fixed_positional_count = not self.star_arg and \
1971 min_positional_args == max_positional_args
1973 code.globalstate.use_utility_code(raise_double_keywords_utility_code)
1974 code.globalstate.use_utility_code(raise_argtuple_invalid_utility_code)
1975 if self.num_required_kw_args:
1976 code.globalstate.use_utility_code(raise_keyword_required_utility_code)
1978 if self.starstar_arg or self.star_arg:
1979 self.generate_stararg_init_code(max_positional_args, code)
1981 # --- optimised code when we receive keyword arguments
1982 if self.num_required_kw_args:
1983 likely_hint = "likely"
1984 else:
1985 likely_hint = "unlikely"
1986 code.putln("if (%s(%s)) {" % (likely_hint, Naming.kwds_cname))
1987 self.generate_keyword_unpacking_code(
1988 min_positional_args, max_positional_args,
1989 has_fixed_positional_count,
1990 positional_args, kw_only_args, argtuple_error_label, code)
1992 # --- optimised code when we do not receive any keyword arguments
1993 if (self.num_required_kw_args and min_positional_args > 0) or min_positional_args == max_positional_args:
1994 # Python raises arg tuple related errors first, so we must
1995 # check the length here
1996 if min_positional_args == max_positional_args and not self.star_arg:
1997 compare = '!='
1998 else:
1999 compare = '<'
2000 code.putln('} else if (PyTuple_GET_SIZE(%s) %s %d) {' % (
2001 Naming.args_cname, compare, min_positional_args))
2002 code.put_goto(argtuple_error_label)
2004 if self.num_required_kw_args:
2005 # pure error case: keywords required but not passed
2006 if max_positional_args > min_positional_args and not self.star_arg:
2007 code.putln('} else if (PyTuple_GET_SIZE(%s) > %d) {' % (
2008 Naming.args_cname, max_positional_args))
2009 code.put_goto(argtuple_error_label)
2010 code.putln('} else {')
2011 for i, arg in enumerate(kw_only_args):
2012 if not arg.default:
2013 # required keyword-only argument missing
2014 code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' % (
2015 self.name.utf8encode(),
2016 arg.name_entry.pystring_cname))
2017 code.putln(code.error_goto(self.pos))
2018 break
2020 elif min_positional_args == max_positional_args:
2021 # parse the exact number of positional arguments from the
2022 # args tuple
2023 code.putln('} else {')
2024 for i, arg in enumerate(positional_args):
2025 item = "PyTuple_GET_ITEM(%s, %d)" % (Naming.args_cname, i)
2026 self.generate_arg_assignment(arg, item, code)
2028 else:
2029 # parse the positional arguments from the variable length
2030 # args tuple
2031 code.putln('} else {')
2032 code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
2033 if self.star_arg:
2034 code.putln('default:')
2035 reversed_args = list(enumerate(positional_args))[::-1]
2036 for i, arg in reversed_args:
2037 if i >= min_positional_args-1:
2038 if min_positional_args > 1:
2039 code.putln('case %2d:' % (i+1)) # pure code beautification
2040 else:
2041 code.put('case %2d: ' % (i+1))
2042 item = "PyTuple_GET_ITEM(%s, %d)" % (Naming.args_cname, i)
2043 self.generate_arg_assignment(arg, item, code)
2044 if min_positional_args == 0:
2045 code.put('case 0: ')
2046 code.putln('break;')
2047 if self.star_arg:
2048 if min_positional_args:
2049 for i in range(min_positional_args-1, -1, -1):
2050 code.putln('case %2d:' % i)
2051 code.put_goto(argtuple_error_label)
2052 else:
2053 code.put('default: ')
2054 code.put_goto(argtuple_error_label)
2055 code.putln('}')
2057 code.putln('}')
2059 if code.label_used(argtuple_error_label):
2060 code.put_goto(success_label)
2061 code.put_label(argtuple_error_label)
2062 code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, PyTuple_GET_SIZE(%s)); ' % (
2063 self.name.utf8encode(), has_fixed_positional_count,
2064 min_positional_args, max_positional_args,
2065 Naming.args_cname))
2066 code.putln(code.error_goto(self.pos))
2068 def generate_stararg_init_code(self, max_positional_args, code):
2069 if self.starstar_arg:
2070 self.starstar_arg.entry.xdecref_cleanup = 0
2071 code.putln('%s = PyDict_New(); if (unlikely(!%s)) return %s;' % (
2072 self.starstar_arg.entry.cname,
2073 self.starstar_arg.entry.cname,
2074 self.error_value()))
2075 if self.star_arg:
2076 self.star_arg.entry.xdecref_cleanup = 0
2077 code.putln('if (PyTuple_GET_SIZE(%s) > %d) {' % (
2078 Naming.args_cname,
2079 max_positional_args))
2080 code.put('%s = PyTuple_GetSlice(%s, %d, PyTuple_GET_SIZE(%s)); ' % (
2081 self.star_arg.entry.cname, Naming.args_cname,
2082 max_positional_args, Naming.args_cname))
2083 if self.starstar_arg:
2084 code.putln("")
2085 code.putln("if (unlikely(!%s)) {" % self.star_arg.entry.cname)
2086 code.put_decref(self.starstar_arg.entry.cname, py_object_type)
2087 code.putln('return %s;' % self.error_value())
2088 code.putln('}')
2089 else:
2090 code.putln("if (unlikely(!%s)) return %s;" % (
2091 self.star_arg.entry.cname, self.error_value()))
2092 code.putln('} else {')
2093 code.put("%s = %s; " % (self.star_arg.entry.cname, Naming.empty_tuple))
2094 code.put_incref(Naming.empty_tuple, py_object_type)
2095 code.putln('}')
2097 def generate_keyword_unpacking_code(self, min_positional_args, max_positional_args,
2098 has_fixed_positional_count, positional_args,
2099 kw_only_args, argtuple_error_label, code):
2100 all_args = tuple(positional_args) + tuple(kw_only_args)
2101 max_args = len(all_args)
2103 code.putln("PyObject* values[%d] = {%s};" % (
2104 max_args, ('0,'*max_args)[:-1]))
2105 code.putln("Py_ssize_t kw_args = PyDict_Size(%s);" %
2106 Naming.kwds_cname)
2108 # parse the tuple and check that it's not too long
2109 code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
2110 if self.star_arg:
2111 code.putln('default:')
2112 for i in range(max_positional_args-1, -1, -1):
2113 code.put('case %2d: ' % (i+1))
2114 code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % (
2115 i, Naming.args_cname, i))
2116 code.putln('case 0: break;')
2117 if not self.star_arg:
2118 code.put('default: ') # more arguments than allowed
2119 code.put_goto(argtuple_error_label)
2120 code.putln('}')
2122 # now fill up the required arguments with values from the kw dict
2123 last_required_arg = -1
2124 for i, arg in enumerate(all_args):
2125 if not arg.default:
2126 last_required_arg = i
2127 if last_required_arg >= 0:
2128 code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
2129 for i, arg in enumerate(all_args[:last_required_arg+1]):
2130 if i <= max_positional_args:
2131 if self.star_arg and i == max_positional_args:
2132 code.putln('default:')
2133 else:
2134 code.putln('case %2d:' % i)
2135 if arg.default:
2136 # handled in ParseOptionalKeywords() below
2137 continue
2138 code.putln('values[%d] = PyDict_GetItem(%s, %s);' % (
2139 i, Naming.kwds_cname, arg.name_entry.pystring_cname))
2140 if i < min_positional_args:
2141 code.putln('if (likely(values[%d])) kw_args--;' % i);
2142 if i == 0:
2143 # special case: we know arg 0 is missing
2144 code.put('else ')
2145 code.put_goto(argtuple_error_label)
2146 else:
2147 # print the correct number of values (args or
2148 # kwargs) that were passed into positional
2149 # arguments up to this point
2150 code.putln('else {')
2151 code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, %d); ' % (
2152 self.name.utf8encode(), has_fixed_positional_count,
2153 min_positional_args, max_positional_args, i))
2154 code.putln(code.error_goto(self.pos))
2155 code.putln('}')
2156 else:
2157 code.putln('if (values[%d]) kw_args--;' % i);
2158 if arg.kw_only and not arg.default:
2159 code.putln('else {')
2160 code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' %(
2161 self.name.utf8encode(), arg.name_entry.pystring_cname))
2162 code.putln(code.error_goto(self.pos))
2163 code.putln('}')
2164 code.putln('}')
2166 code.putln('if (unlikely(kw_args > 0)) {')
2167 # non-positional kw args left in dict: default args, **kwargs or error
2168 if self.star_arg:
2169 code.putln("const Py_ssize_t used_pos_args = (PyTuple_GET_SIZE(%s) < %d) ? PyTuple_GET_SIZE(%s) : %d;" % (
2170 Naming.args_cname, max_positional_args,
2171 Naming.args_cname, max_positional_args))
2172 pos_arg_count = "used_pos_args"
2173 else:
2174 pos_arg_count = "PyTuple_GET_SIZE(%s)" % Naming.args_cname
2175 code.globalstate.use_utility_code(parse_keywords_utility_code)
2176 code.put(
2177 'if (unlikely(__Pyx_ParseOptionalKeywords(%s, %s, %s, values, %s, "%s") < 0)) ' % (
2178 Naming.kwds_cname,
2179 Naming.pykwdlist_cname,
2180 self.starstar_arg and self.starstar_arg.entry.cname or '0',
2181 pos_arg_count,
2182 self.name.utf8encode()))
2183 code.putln(code.error_goto(self.pos))
2184 code.putln('}')
2186 # convert arg values to their final type and assign them
2187 for i, arg in enumerate(all_args):
2188 if arg.default:
2189 code.putln("if (values[%d]) {" % i)
2190 self.generate_arg_assignment(arg, "values[%d]" % i, code)
2191 if arg.default:
2192 code.putln('}')
2194 def generate_argument_conversion_code(self, code):
2195 # Generate code to convert arguments from
2196 # signature type to declared type, if needed.
2197 for arg in self.args:
2198 if arg.needs_conversion:
2199 self.generate_arg_conversion(arg, code)
2201 def generate_arg_conversion(self, arg, code):
2202 # Generate conversion code for one argument.
2203 old_type = arg.hdr_type
2204 new_type = arg.type
2205 if old_type.is_pyobject:
2206 if arg.default:
2207 code.putln("if (%s) {" % arg.hdr_cname)
2208 else:
2209 code.putln("assert(%s); {" % arg.hdr_cname)
2210 self.generate_arg_conversion_from_pyobject(arg, code)
2211 code.putln("}")
2212 elif new_type.is_pyobject:
2213 self.generate_arg_conversion_to_pyobject(arg, code)
2214 else:
2215 if new_type.assignable_from(old_type):
2216 code.putln(
2217 "%s = %s;" % (arg.entry.cname, arg.hdr_cname))
2218 else:
2219 error(arg.pos,
2220 "Cannot convert 1 argument from '%s' to '%s'" %
2221 (old_type, new_type))
2223 def generate_arg_conversion_from_pyobject(self, arg, code):
2224 new_type = arg.type
2225 func = new_type.from_py_function
2226 # copied from CoerceFromPyTypeNode
2227 if func:
2228 code.putln("%s = %s(%s); %s" % (
2229 arg.entry.cname,
2230 func,
2231 arg.hdr_cname,
2232 code.error_goto_if(new_type.error_condition(arg.entry.cname), arg.pos)))
2233 else:
2234 error(arg.pos,
2235 "Cannot convert Python object argument to type '%s'"
2236 % new_type)
2238 def generate_arg_conversion_to_pyobject(self, arg, code):
2239 old_type = arg.hdr_type
2240 func = old_type.to_py_function
2241 if func:
2242 code.putln("%s = %s(%s); %s" % (
2243 arg.entry.cname,
2244 func,
2245 arg.hdr_cname,
2246 code.error_goto_if_null(arg.entry.cname, arg.pos)))
2247 else:
2248 error(arg.pos,
2249 "Cannot convert argument of type '%s' to Python object"
2250 % old_type)
2252 def generate_argument_type_tests(self, code):
2253 # Generate type tests for args whose signature
2254 # type is PyObject * and whose declared type is
2255 # a subtype thereof.
2256 for arg in self.args:
2257 if arg.needs_type_test:
2258 self.generate_arg_type_test(arg, code)
2260 def generate_arg_type_test(self, arg, code):
2261 # Generate type test for one argument.
2262 if arg.type.typeobj_is_available():
2263 typeptr_cname = arg.type.typeptr_cname
2264 arg_code = "((PyObject *)%s)" % arg.entry.cname
2265 code.putln(
2266 'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % (
2267 arg_code,
2268 typeptr_cname,
2269 not arg.not_none,
2270 arg.name,
2271 arg.type.is_builtin_type,
2272 code.error_goto(arg.pos)))
2273 else:
2274 error(arg.pos, "Cannot test type of extern C class "
2275 "without type object name specification")
2277 def error_value(self):
2278 return self.entry.signature.error_value
2280 def caller_will_check_exceptions(self):
2281 return 1
2283 class OverrideCheckNode(StatNode):
2284 # A Node for dispatching to the def method if it
2285 # is overriden.
2287 # py_func
2289 # args
2290 # func_temp
2291 # body
2293 child_attrs = ['body']
2295 body = None
2297 def analyse_expressions(self, env):
2298 self.args = env.arg_entries
2299 if self.py_func.is_module_scope:
2300 first_arg = 0
2301 else:
2302 first_arg = 1
2303 import ExprNodes
2304 self.func_node = ExprNodes.PyTempNode(self.pos, env)
2305 call_tuple = ExprNodes.TupleNode(self.pos, args=[ExprNodes.NameNode(self.pos, name=arg.name) for arg in self.args[first_arg:]])
2306 call_node = ExprNodes.SimpleCallNode(self.pos,
2307 function=self.func_node,
2308 args=[ExprNodes.NameNode(self.pos, name=arg.name) for arg in self.args[first_arg:]])
2309 self.body = ReturnStatNode(self.pos, value=call_node)
2310 self.body.analyse_expressions(env)
2312 def generate_execution_code(self, code):
2313 # Check to see if we are an extension type
2314 if self.py_func.is_module_scope:
2315 self_arg = "((PyObject *)%s)" % Naming.module_cname
2316 else:
2317 self_arg = "((PyObject *)%s)" % self.args[0].cname
2318 code.putln("/* Check if called by wrapper */")
2319 code.putln("if (unlikely(%s)) ;" % Naming.skip_dispatch_cname)
2320 code.putln("/* Check if overriden in Python */")
2321 if self.py_func.is_module_scope:
2322 code.putln("else {")
2323 else:
2324 code.putln("else if (unlikely(Py_TYPE(%s)->tp_dictoffset != 0)) {" % self_arg)
2325 err = code.error_goto_if_null(self.func_node.result(), self.pos)
2326 # need to get attribute manually--scope would return cdef method
2327 code.putln("%s = PyObject_GetAttr(%s, %s); %s" % (self.func_node.result(), self_arg, self.py_func.interned_attr_cname, err))
2328 # It appears that this type is not anywhere exposed in the Python/C API
2329 is_builtin_function_or_method = '(strcmp(Py_TYPE(%s)->tp_name, "builtin_function_or_method") == 0)' % self.func_node.result()
2330 is_overridden = '(PyCFunction_GET_FUNCTION(%s) != (void *)&%s)' % (self.func_node.result(), self.py_func.entry.func_cname)
2331 code.putln('if (!%s || %s) {' % (is_builtin_function_or_method, is_overridden))
2332 self.body.generate_execution_code(code)
2333 code.putln('}')
2334 code.put_decref_clear(self.func_node.result(), PyrexTypes.py_object_type)
2335 code.putln("}")
2337 class ClassDefNode(StatNode, BlockNode):
2338 pass
2340 class PyClassDefNode(ClassDefNode):
2341 # A Python class definition.
2343 # name EncodedString Name of the class
2344 # doc string or None
2345 # body StatNode Attribute definition code
2346 # entry Symtab.Entry
2347 # scope PyClassScope
2349 # The following subnodes are constructed internally:
2351 # dict DictNode Class dictionary
2352 # classobj ClassNode Class object
2353 # target NameNode Variable to assign class object to
2355 child_attrs = ["body", "dict", "classobj", "target"]
2357 def __init__(self, pos, name, bases, doc, body):
2358 StatNode.__init__(self, pos)
2359 self.name = name
2360 self.doc = doc
2361 self.body = body
2362 import ExprNodes
2363 self.dict = ExprNodes.DictNode(pos, key_value_pairs = [])
2364 if self.doc and Options.docstrings:
2365 doc = embed_position(self.pos, self.doc)
2366 doc_node = ExprNodes.StringNode(pos, value = doc)
2367 else:
2368 doc_node = None
2369 self.classobj = ExprNodes.ClassNode(pos, name = name,
2370 bases = bases, dict = self.dict, doc = doc_node)
2371 self.target = ExprNodes.NameNode(pos, name = name)
2373 def as_cclass(self):
2374 """
2375 Return this node as if it were declared as an extension class
2376 """
2377 bases = self.classobj.bases.args
2378 if len(bases) == 0:
2379 base_class_name = None
2380 base_class_module = None
2381 elif len(bases) == 1:
2382 base = bases[0]
2383 path = []
2384 from ExprNodes import AttributeNode, NameNode
2385 while isinstance(base, AttributeNode):
2386 path.insert(0, base.attribute)
2387 base = base.obj
2388 if isinstance(base, NameNode):
2389 path.insert(0, base.name)
2390 base_class_name = path[-1]
2391 if len(path) > 1:
2392 base_class_module = u'.'.join(path[:-1])
2393 else:
2394 base_class_module = None
2395 else:
2396 error(self.classobj.bases.args.pos, "Invalid base class")
2397 else:
2398 error(self.classobj.bases.args.pos, "C class may only have one base class")
2399 return None
2401 return CClassDefNode(self.pos,
2402 visibility = 'private',
2403 module_name = None,
2404 class_name = self.name,
2405 base_class_module = base_class_module,
2406 base_class_name = base_class_name,
2407 body = self.body,
2408 in_pxd = False,
2409 doc = self.doc)
2411 def create_scope(self, env):
2412 genv = env
2413 while env.is_py_class_scope or env.is_c_class_scope:
2414 env = env.outer_scope
2415 cenv = self.scope = PyClassScope(name = self.name, outer_scope = genv)
2416 return cenv
2418 def analyse_declarations(self, env):
2419 self.target.analyse_target_declaration(env)
2420 cenv = self.create_scope(env)
2421 cenv.class_obj_cname = self.target.entry.cname
2422 self.body.analyse_declarations(cenv)
2424 def analyse_expressions(self, env):
2425 self.dict.analyse_expressions(env)
2426 self.classobj.analyse_expressions(env)
2427 genv = env.global_scope()
2428 cenv = self.scope
2429 cenv.class_dict_cname = self.dict.result()
2430 cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
2431 self.body.analyse_expressions(cenv)
2432 self.target.analyse_target_expression(env, self.classobj)
2433 self.dict.release_temp(env)
2434 #self.classobj.release_temp(env)
2435 #self.target.release_target_temp(env)
2437 def generate_function_definitions(self, env, code):
2438 self.generate_py_string_decls(self.scope, code)
2439 self.body.generate_function_definitions(self.scope, code)
2441 def generate_execution_code(self, code):
2442 self.dict.generate_evaluation_code(code)
2443 self.classobj.generate_evaluation_code(code)
2444 self.body.generate_execution_code(code)
2445 self.target.generate_assignment_code(self.classobj, code)
2446 self.dict.generate_disposal_code(code)
2447 self.dict.free_temps(code)
2450 class CClassDefNode(ClassDefNode):
2451 # An extension type definition.
2453 # visibility 'private' or 'public' or 'extern'
2454 # typedef_flag boolean
2455 # api boolean
2456 # module_name string or None For import of extern type objects
2457 # class_name string Unqualified name of class
2458 # as_name string or None Name to declare as in this scope
2459 # base_class_module string or None Module containing the base class
2460 # base_class_name string or None Name of the base class
2461 # objstruct_name string or None Specified C name of object struct
2462 # typeobj_name string or None Specified C name of type object
2463 # in_pxd boolean Is in a .pxd file
2464 # doc string or None
2465 # body StatNode or None
2466 # entry Symtab.Entry
2467 # base_type PyExtensionType or None
2468 # buffer_defaults_node DictNode or None Declares defaults for a buffer
2469 # buffer_defaults_pos
2471 child_attrs = ["body"]
2472 buffer_defaults_node = None
2473 buffer_defaults_pos = None
2474 typedef_flag = False
2475 api = False
2476 objstruct_name = None
2477 typeobj_name = None
2479 def analyse_declarations(self, env):
2480 #print "CClassDefNode.analyse_declarations:", self.class_name
2481 #print "...visibility =", self.visibility
2482 #print "...module_name =", self.module_name
2484 import Buffer
2485 if self.buffer_defaults_node:
2486 buffer_defaults = Buffer.analyse_buffer_options(self.buffer_defaults_pos,
2487 env, [], self.buffer_defaults_node,
2488 need_complete=False)
2489 else:
2490 buffer_defaults = None
2492 if env.in_cinclude and not self.objstruct_name:
2493 error(self.pos, "Object struct name specification required for "
2494 "C class defined in 'extern from' block")
2495 self.base_type = None
2496 # Now that module imports are cached, we need to
2497 # import the modules for extern classes.
2498 if self.module_name:
2499 self.module = None
2500 for module in env.cimported_modules:
2501 if module.name == self.module_name:
2502 self.module = module
2503 if self.module is None:
2504 self.module = ModuleScope(self.module_name, None, env.context)
2505 self.module.has_extern_class = 1
2506 env.cimported_modules.append(self.module)
2508 if self.base_class_name:
2509 if self.base_class_module:
2510 base_class_scope = env.find_module(self.base_class_module, self.pos)
2511 else:
2512 base_class_scope = env
2513 if base_class_scope:
2514 base_class_entry = base_class_scope.find(self.base_class_name, self.pos)
2515 if base_class_entry:
2516 if not base_class_entry.is_type:
2517 error(self.pos, "'%s' is not a type name" % self.base_class_name)
2518 elif not base_class_entry.type.is_extension_type:
2519 error(self.pos, "'%s' is not an extension type" % self.base_class_name)
2520 elif not base_class_entry.type.is_complete():
2521 error(self.pos, "Base class '%s' is incomplete" % self.base_class_name)
2522 else:
2523 self.base_type = base_class_entry.type
2524 has_body = self.body is not None
2525 if self.module_name and self.visibility != 'extern':
2526 module_path = self.module_name.split(".")
2527 home_scope = env.find_imported_module(module_path, self.pos)
2528 if not home_scope:
2529 return
2530 else:
2531 home_scope = env
2532 self.entry = home_scope.declare_c_class(
2533 name = self.class_name,
2534 pos = self.pos,
2535 defining = has_body and self.in_pxd,
2536 implementing = has_body and not self.in_pxd,
2537 module_name = self.module_name,
2538 base_type = self.base_type,
2539 objstruct_cname = self.objstruct_name,
2540 typeobj_cname = self.typeobj_name,
2541 visibility = self.visibility,
2542 typedef_flag = self.typedef_flag,
2543 api = self.api,
2544 buffer_defaults = buffer_defaults)
2545 if home_scope is not env and self.visibility == 'extern':
2546 env.add_imported_entry(self.class_name, self.entry, pos)
2547 scope = self.entry.type.scope
2549 if self.doc and Options.docstrings:
2550 scope.doc = embed_position(self.pos, self.doc)
2552 if has_body:
2553 self.body.analyse_declarations(scope)
2554 if self.in_pxd:
2555 scope.defined = 1
2556 else:
2557 scope.implemented = 1
2558 env.allocate_vtable_names(self.entry)
2560 def analyse_expressions(self, env):
2561 if self.body:
2562 scope = self.entry.type.scope
2563 self.body.analyse_expressions(scope)
2565 def generate_function_definitions(self, env, code):
2566 self.generate_py_string_decls(self.entry.type.scope, code)
2567 if self.body:
2568 self.body.generate_function_definitions(
2569 self.entry.type.scope, code)
2571 def generate_execution_code(self, code):
2572 # This is needed to generate evaluation code for
2573 # default values of method arguments.
2574 if self.body:
2575 self.body.generate_execution_code(code)
2577 def annotate(self, code):
2578 if self.body:
2579 self.body.annotate(code)
2582 class PropertyNode(StatNode):
2583 # Definition of a property in an extension type.
2585 # name string
2586 # doc EncodedString or None Doc string
2587 # body StatListNode
2589 child_attrs = ["body"]
2591 def analyse_declarations(self, env):
2592 entry = env.declare_property(self.name, self.doc, self.pos)
2593 if entry:
2594 if self.doc and Options.docstrings:
2595 doc_entry = env.get_string_const(
2596 self.doc, identifier = False)
2597 entry.doc_cname = doc_entry.cname
2598 self.body.analyse_declarations(entry.scope)
2600 def analyse_expressions(self, env):
2601 self.body.analyse_expressions(env)
2603 def generate_function_definitions(self, env, code):
2604 self.body.generate_function_definitions(env, code)
2606 def generate_execution_code(self, code):
2607 pass
2609 def annotate(self, code):
2610 self.body.annotate(code)
2613 class GlobalNode(StatNode):
2614 # Global variable declaration.
2616 # names [string]
2618 child_attrs = []
2620 def analyse_declarations(self, env):
2621 for name in self.names:
2622 env.declare_global(name, self.pos)
2624 def analyse_expressions(self, env):
2625 pass
2627 def generate_execution_code(self, code):
2628 pass
2631 class ExprStatNode(StatNode):
2632 # Expression used as a statement.
2634 # expr ExprNode
2636 child_attrs = ["expr"]
2638 def analyse_declarations(self, env):
2639 import ExprNodes
2640 if isinstance(self.expr, ExprNodes.GeneralCallNode):
2641 func = self.expr.function.as_cython_attribute()
2642 if func == u'declare':
2643 args, kwds = self.expr.explicit_args_kwds()
2644 if len(args):
2645 error(self.expr.pos, "Variable names must be specified.")
2646 for var, type_node in kwds.key_value_pairs:
2647 type = type_node.analyse_as_type(env)
2648 if type is None:
2649 error(type_node.pos, "Unknown type")
2650 else:
2651 env.declare_var(var.value, type, var.pos, is_cdef = True)
2652 self.__class__ = PassStatNode
2654 def analyse_expressions(self, env):
2655 self.expr.analyse_expressions(env)
2656 self.expr.release_temp(env)
2658 def generate_execution_code(self, code):
2659 self.expr.generate_evaluation_code(code)
2660 if not self.expr.is_temp and self.expr.result():
2661 code.putln("%s;" % self.expr.result())
2662 self.expr.generate_disposal_code(code)
2663 self.expr.free_temps(code)
2665 def annotate(self, code):
2666 self.expr.annotate(code)
2669 class AssignmentNode(StatNode):
2670 # Abstract base class for assignment nodes.
2672 # The analyse_expressions and generate_execution_code
2673 # phases of assignments are split into two sub-phases
2674 # each, to enable all the right hand sides of a
2675 # parallel assignment to be evaluated before assigning
2676 # to any of the left hand sides.
2678 def analyse_expressions(self, env):
2679 self.analyse_types(env)
2680 self.allocate_rhs_temps(env)
2681 self.allocate_lhs_temps(env)
2683 # def analyse_expressions(self, env):
2684 # self.analyse_expressions_1(env)
2685 # self.analyse_expressions_2(env)
2687 def generate_execution_code(self, code):
2688 self.generate_rhs_evaluation_code(code)
2689 self.generate_assignment_code(code)
2692 class SingleAssignmentNode(AssignmentNode):
2693 # The simplest case:
2695 # a = b
2697 # lhs ExprNode Left hand side
2698 # rhs ExprNode Right hand side
2699 # first bool Is this guaranteed the first assignment to lhs?
2701 child_attrs = ["lhs", "rhs"]
2702 first = False
2703 declaration_only = False
2705 def analyse_declarations(self, env):
2706 import ExprNodes
2708 # handle declarations of the form x = cython.foo()
2709 if isinstance(self.rhs, ExprNodes.CallNode):
2710 func_name = self.rhs.function.as_cython_attribute()
2711 if func_name:
2712 args, kwds = self.rhs.explicit_args_kwds()
2714 if func_name in ['declare', 'typedef']:
2715 if len(args) > 2 or kwds is not None:
2716 error(rhs.pos, "Can only declare one type at a time.")
2717 return
2718 type = args[0].analyse_as_type(env)
2719 if type is None:
2720 error(args[0].pos, "Unknown type")
2721 return
2722 lhs = self.lhs
2723 if func_name == 'declare':
2724 if isinstance(lhs, ExprNodes.NameNode):
2725 vars = [(lhs.name, lhs.pos)]
2726 elif isinstance(lhs, ExprNodes.TupleNode):
2727 vars = [(var.name, var.pos) for var in lhs.args]
2728 else:
2729 error(lhs.pos, "Invalid declaration")
2730 return
2731 for var, pos in vars:
2732 env.declare_var(var, type, pos, is_cdef = True)
2733 if len(args) == 2:
2734 # we have a value
2735 self.rhs = args[1]
2736 else:
2737 self.declaration_only = True
2738 else:
2739 self.declaration_only = True
2740 if not isinstance(lhs, ExprNodes.NameNode):
2741 error(lhs.pos, "Invalid declaration.")
2742 env.declare_typedef(lhs.name, type, self.pos, visibility='private')
2744 elif func_name in ['struct', 'union']:
2745 self.declaration_only = True
2746 if len(args) > 0 or kwds is None:
2747 error(rhs.pos, "Struct or union members must be given by name.")
2748 return
2749 members = []
2750 for member, type_node in kwds.key_value_pairs:
2751 type = type_node.analyse_as_type(env)
2752 if type is None:
2753 error(type_node.pos, "Unknown type")
2754 else:
2755 members.append((member.value, type, member.pos))
2756 if len(members) < len(kwds.key_value_pairs):
2757 return
2758 if not isinstance(self.lhs, ExprNodes.NameNode):
2759 error(self.lhs.pos, "Invalid declaration.")
2760 name = self.lhs.name
2761 scope = StructOrUnionScope(name)
2762 env.declare_struct_or_union(name, func_name, scope, False, self.rhs.pos)
2763 for member, type, pos in members:
2764 scope.declare_var(member, type, pos)
2766 if self.declaration_only:
2767 return
2768 else:
2769 self.lhs.analyse_target_declaration(env)
2771 def analyse_types(self, env, use_temp = 0):
2772 self.rhs.analyse_types(env)
2773 self.lhs.analyse_target_types(env)
2774 self.lhs.gil_assignment_check(env)
2775 self.rhs = self.rhs.coerce_to(self.lhs.type, env)
2776 if use_temp:
2777 self.rhs = self.rhs.coerce_to_temp(env)
2779 def allocate_rhs_temps(self, env):
2780 self.rhs.allocate_temps(env)
2782 def allocate_lhs_temps(self, env):
2783 self.lhs.allocate_target_temps(env, self.rhs)
2784 #self.lhs.release_target_temp(env)
2785 #self.rhs.release_temp(env)
2787 # def analyse_expressions_1(self, env, use_temp = 0):
2788 # self.rhs.analyse_types(env)
2789 # self.lhs.analyse_target_types(env)
2790 # self.rhs = self.rhs.coerce_to(self.lhs.type, env)
2791 # if use_temp:
2792 # self.rhs = self.rhs.coerce_to_temp(env)
2793 # self.rhs.allocate_temps(env)
2795 # def analyse_expressions_2(self, env):
2796 # self.lhs.allocate_target_temps(env)
2797 # self.lhs.release_target_temp(env)
2798 # self.rhs.release_temp(env)
2800 def generate_rhs_evaluation_code(self, code):
2801 self.rhs.generate_evaluation_code(code)
2803 def generate_assignment_code(self, code):
2804 self.lhs.generate_assignment_code(self.rhs, code)
2806 def annotate(self, code):
2807 self.lhs.annotate(code)
2808 self.rhs.annotate(code)
2811 class CascadedAssignmentNode(AssignmentNode):
2812 # An assignment with multiple left hand sides:
2814 # a = b = c
2816 # lhs_list [ExprNode] Left hand sides
2817 # rhs ExprNode Right hand sides
2819 # Used internally:
2821 # coerced_rhs_list [ExprNode] RHS coerced to type of each LHS
2823 child_attrs = ["lhs_list", "rhs", "coerced_rhs_list"]
2824 coerced_rhs_list = None
2826 def analyse_declarations(self, env):
2827 for lhs in self.lhs_list:
2828 lhs.analyse_target_declaration(env)
2830 def analyse_types(self, env, use_temp = 0):
2831 self.rhs.analyse_types(env)
2832 if use_temp:
2833 self.rhs = self.rhs.coerce_to_temp(env)
2834 else:
2835 self.rhs = self.rhs.coerce_to_simple(env)
2836 from ExprNodes import CloneNode
2837 self.coerced_rhs_list = []
2838 for lhs in self.lhs_list:
2839 lhs.analyse_target_types(env)
2840 lhs.gil_assignment_check(env)
2841 rhs = CloneNode(self.rhs)
2842 rhs = rhs.coerce_to(lhs.type, env)
2843 self.coerced_rhs_list.append(rhs)
2845 def allocate_rhs_temps(self, env):
2846 self.rhs.allocate_temps(env)
2848 def allocate_lhs_temps(self, env):
2849 for lhs, rhs in zip(self.lhs_list, self.coerced_rhs_list):
2850 rhs.allocate_temps(env)
2851 lhs.allocate_target_temps(env, rhs)
2852 #lhs.release_target_temp(env)
2853 #rhs.release_temp(env)
2854 self.rhs.release_temp(env)
2856 # def analyse_expressions_1(self, env, use_temp = 0):
2857 # self.rhs.analyse_types(env)
2858 # if use_temp:
2859 # self.rhs = self.rhs.coerce_to_temp(env)
2860 # else:
2861 # self.rhs = self.rhs.coerce_to_simple(env)
2862 # self.rhs.allocate_temps(env)
2864 # def analyse_expressions_2(self, env):
2865 # from ExprNodes import CloneNode
2866 # self.coerced_rhs_list = []
2867 # for lhs in self.lhs_list:
2868 # lhs.analyse_target_types(env)
2869 # rhs = CloneNode(self.rhs)
2870 # rhs = rhs.coerce_to(lhs.type, env)
2871 # self.coerced_rhs_list.append(rhs)
2872 # rhs.allocate_temps(env)
2873 # lhs.allocate_target_temps(env)
2874 # lhs.release_target_temp(env)
2875 # rhs.release_temp(env)
2876 # self.rhs.release_temp(env)
2878 def generate_rhs_evaluation_code(self, code):
2879 self.rhs.generate_evaluation_code(code)
2881 def generate_assignment_code(self, code):
2882 for i in range(len(self.lhs_list)):
2883 lhs = self.lhs_list[i]
2884 rhs = self.coerced_rhs_list[i]
2885 rhs.generate_evaluation_code(code)
2886 lhs.generate_assignment_code(rhs, code)
2887 # Assignment has disposed of the cloned RHS
2888 self.rhs.generate_disposal_code(code)
2889 self.rhs.free_temps(code)
2891 def annotate(self, code):
2892 for i in range(len(self.lhs_list)):
2893 lhs = self.lhs_list[i].annotate(code)
2894 rhs = self.coerced_rhs_list[i].annotate(code)
2895 self.rhs.annotate(code)
2898 class ParallelAssignmentNode(AssignmentNode):
2899 # A combined packing/unpacking assignment:
2901 # a, b, c = d, e, f
2903 # This has been rearranged by the parser into
2905 # a = d ; b = e ; c = f
2907 # but we must evaluate all the right hand sides
2908 # before assigning to any of the left hand sides.
2910 # stats [AssignmentNode] The constituent assignments
2912 child_attrs = ["stats"]
2914 def analyse_declarations(self, env):
2915 for stat in self.stats:
2916 stat.analyse_declarations(env)
2918 def analyse_expressions(self, env):
2919 for stat in self.stats:
2920 stat.analyse_types(env, use_temp = 1)
2921 stat.allocate_rhs_temps(env)
2922 for stat in self.stats:
2923 stat.allocate_lhs_temps(env)
2925 # def analyse_expressions(self, env):
2926 # for stat in self.stats:
2927 # stat.analyse_expressions_1(env, use_temp = 1)
2928 # for stat in self.stats:
2929 # stat.analyse_expressions_2(env)
2931 def generate_execution_code(self, code):
2932 for stat in self.stats:
2933 stat.generate_rhs_evaluation_code(code)
2934 for stat in self.stats:
2935 stat.generate_assignment_code(code)
2937 def annotate(self, code):
2938 for stat in self.stats:
2939 stat.annotate(code)
2942 class InPlaceAssignmentNode(AssignmentNode):
2943 # An in place arithmatic operand:
2945 # a += b
2946 # a -= b
2947 # ...
2949 # lhs ExprNode Left hand side
2950 # rhs ExprNode Right hand side
2951 # op char one of "+-*/%^&|"
2952 # dup (ExprNode) copy of lhs used for operation (auto-generated)
2954 # This code is a bit tricky because in order to obey Python
2955 # semantics the sub-expressions (e.g. indices) of the lhs must
2956 # not be evaluated twice. So we must re-use the values calculated
2957 # in evaluation phase for the assignment phase as well.
2958 # Fortunately, the type of the lhs node is fairly constrained
2959 # (it must be a NameNode, AttributeNode, or IndexNode).
2961 child_attrs = ["lhs", "rhs"]
2962 dup = None
2964 def analyse_declarations(self, env):
2965 self.lhs.analyse_target_declaration(env)
2967 def analyse_types(self, env):
2968 self.dup = self.create_dup_node(env) # re-assigns lhs to a shallow copy
2969 self.rhs.analyse_types(env)
2970 self.lhs.analyse_target_types(env)
2971 if Options.incref_local_binop and self.dup.type.is_pyobject:
2972 self.dup = self.dup.coerce_to_temp(env)
2974 def allocate_rhs_temps(self, env):
2975 import ExprNodes
2976 if self.lhs.type.is_pyobject:
2977 self.rhs = self.rhs.coerce_to_pyobject(env)
2978 elif self.rhs.type.is_pyobject:
2979 self.rhs = self.rhs.coerce_to(self.lhs.type, env)
2980 if self.lhs.type.is_pyobject:
2981 self.result_value = ExprNodes.PyTempNode(self.pos, env).coerce_to(self.lhs.type, env)
2982 self.result_value.allocate_temps(env)
2983 # if use_temp:
2984 # self.rhs = self.rhs.coerce_to_temp(env)
2985 self.rhs.allocate_temps(env)
2986 self.dup.allocate_subexpr_temps(env)
2987 self.dup.allocate_temp(env)
2989 def allocate_lhs_temps(self, env):
2990 self.lhs.allocate_target_temps(env, self.rhs)
2991 # self.lhs.release_target_temp(env)
2992 self.dup.release_temp(env)
2993 if self.dup.is_temp:
2994 self.dup.release_subexpr_temps(env)
2995 # self.rhs.release_temp(env)
2996 if self.lhs.type.is_pyobject:
2997 self.result_value.release_temp(env)
2999 def generate_execution_code(self, code):
3000 self.rhs.generate_evaluation_code(code)
3001 self.dup.generate_subexpr_evaluation_code(code)
3002 # self.dup.generate_result_code is run only if it is not buffer access
3003 if self.operator == "**":
3004 extra = ", Py_None"
3005 else:
3006 extra = ""
3007 import ExprNodes
3008 if self.lhs.type.is_pyobject:
3009 if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
3010 error(self.pos, "In-place operators not allowed on object buffers in this release.")
3011 self.dup.generate_result_code(code)
3012 code.putln(
3013 "%s = %s(%s, %s%s); %s" % (
3014 self.result_value.result(),
3015 self.py_operation_function(),
3016 self.dup.py_result(),
3017 self.rhs.py_result(),
3018 extra,
3019 code.error_goto_if_null(self.result_value.py_result(), self.pos)))
3020 self.result_value.generate_evaluation_code(code) # May be a type check...
3021 self.rhs.generate_disposal_code(code)
3022 self.rhs.free_temps(code)
3023 self.dup.generate_disposal_code(code)
3024 self.dup.free_temps(code)
3025 self.lhs.generate_assignment_code(self.result_value, code)
3026 else:
3027 c_op = self.operator
3028 if c_op == "//":
3029 c_op = "/"
3030 elif c_op == "**":
3031 if self.lhs.type.is_int and self.rhs.type.is_int:
3032 error(self.pos, "** with two C int types is ambiguous")
3033 else:
3034 error(self.pos, "No C inplace power operator")
3035 # have to do assignment directly to avoid side-effects
3036 if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
3037 self.lhs.generate_buffer_setitem_code(self.rhs, code, c_op)
3038 else:
3039 self.dup.generate_result_code(code)
3040 code.putln("%s %s= %s;" % (self.lhs.result(), c_op, self.rhs.result()) )
3041 self.rhs.generate_disposal_code(code)
3042 self.rhs.free_temps(code)
3043 if self.dup.is_temp:
3044 self.dup.generate_subexpr_disposal_code(code)
3045 self.dup.free_subexpr_temps(code)
3047 def create_dup_node(self, env):
3048 import ExprNodes
3049 self.dup = self.lhs
3050 self.dup.analyse_types(env)
3051 if isinstance(self.lhs, ExprNodes.NameNode):
3052 target_lhs = ExprNodes.NameNode(self.dup.pos,
3053 name = self.dup.name,
3054 is_temp = self.dup.is_temp,
3055 entry = self.dup.entry)
3056 elif isinstance(self.lhs, ExprNodes.AttributeNode):
3057 target_lhs = ExprNodes.AttributeNode(self.dup.pos,
3058 obj = ExprNodes.CloneNode(self.lhs.obj),
3059 attribute = self.dup.attribute,
3060 is_temp = self.dup.is_temp)
3061 elif isinstance(self.lhs, ExprNodes.IndexNode):
3062 if self.lhs.index:
3063 index = ExprNodes.CloneNode(self.lhs.index)
3064 else:
3065 index = None
3066 if self.lhs.indices:
3067 indices = [ExprNodes.CloneNode(x) for x in self.lhs.indices]
3068 else:
3069 indices = []
3070 target_lhs = ExprNodes.IndexNode(self.dup.pos,
3071 base = ExprNodes.CloneNode(self.dup.base),
3072 index = index,
3073 indices = indices,
3074 is_temp = self.dup.is_temp)
3075 else:
3076 assert False
3077 self.lhs = target_lhs
3078 return self.dup
3080 def py_operation_function(self):
3081 return self.py_functions[self.operator]
3083 py_functions = {
3084 "|": "PyNumber_InPlaceOr",
3085 "^": "PyNumber_InPlaceXor",
3086 "&": "PyNumber_InPlaceAnd",
3087 "+": "PyNumber_InPlaceAdd",
3088 "-": "PyNumber_InPlaceSubtract",
3089 "*": "PyNumber_InPlaceMultiply",
3090 "/": "PyNumber_InPlaceDivide",
3091 "%": "PyNumber_InPlaceRemainder",
3092 "<<": "PyNumber_InPlaceLshift",
3093 ">>": "PyNumber_InPlaceRshift",
3094 "**": "PyNumber_InPlacePower",
3095 "//": "PyNumber_InPlaceFloorDivide",
3098 def annotate(self, code):
3099 self.lhs.annotate(code)
3100 self.rhs.annotate(code)
3101 self.dup.annotate(code)
3104 class PrintStatNode(StatNode):
3105 # print statement
3107 # arg_tuple TupleNode
3108 # append_newline boolean
3110 child_attrs = ["arg_tuple"]
3112 def analyse_expressions(self, env):
3113 self.arg_tuple.analyse_expressions(env)
3114 self.arg_tuple = self.arg_tuple.coerce_to_pyobject(env)
3115 self.arg_tuple.release_temp(env)
3116 env.use_utility_code(printing_utility_code)
3117 self.gil_check(env)
3119 gil_message = "Python print statement"
3121 def generate_execution_code(self, code):
3122 self.arg_tuple.generate_evaluation_code(code)
3123 code.putln(
3124 "if (__Pyx_Print(%s, %d) < 0) %s" % (
3125 self.arg_tuple.py_result(),
3126 self.append_newline,
3127 code.error_goto(self.pos)))
3128 self.arg_tuple.generate_disposal_code(code)
3129 self.arg_tuple.free_temps(code)
3131 def annotate(self, code):
3132 self.arg_tuple.annotate(code)
3135 class ExecStatNode(StatNode):
3136 # exec statement
3138 # args [ExprNode]
3140 child_attrs = ["args"]
3142 def analyse_expressions(self, env):
3143 for i, arg in enumerate(self.args):
3144 arg.analyse_expressions(env)
3145 arg = arg.coerce_to_pyobject(env)
3146 arg.release_temp(env)
3147 self.args[i] = arg
3148 self.temp_result = env.allocate_temp_pyobject()
3149 env.release_temp(self.temp_result)
3150 env.use_utility_code(Builtin.pyexec_utility_code)
3151 self.gil_check(env)
3153 gil_message = "Python exec statement"
3155 def generate_execution_code(self, code):
3156 args = []
3157 for arg in self.args:
3158 arg.generate_evaluation_code(code)
3159 args.append( arg.py_result() )
3160 args = tuple(args + ['0', '0'][:3-len(args)])
3161 code.putln("%s = __Pyx_PyRun(%s, %s, %s);" % (
3162 (self.temp_result,) + args))
3163 for arg in self.args:
3164 arg.generate_disposal_code(code)
3165 arg.free_temps(code)
3166 code.putln(
3167 code.error_goto_if_null(self.temp_result, self.pos))
3168 code.put_decref_clear(self.temp_result, py_object_type)
3170 def annotate(self, code):
3171 for arg in self.args:
3172 arg.annotate(code)
3175 class DelStatNode(StatNode):
3176 # del statement
3178 # args [ExprNode]
3180 child_attrs = ["args"]
3182 def analyse_declarations(self, env):
3183 for arg in self.args:
3184 arg.analyse_target_declaration(env)
3186 def analyse_expressions(self, env):
3187 for arg in self.args:
3188 arg.analyse_target_expression(env, None)
3189 if arg.type.is_pyobject:
3190 self.gil_check(env)
3191 else:
3192 error(arg.pos, "Deletion of non-Python object")
3193 #arg.release_target_temp(env)
3195 gil_message = "Deleting Python object"
3197 def generate_execution_code(self, code):
3198 for arg in self.args:
3199 if arg.type.is_pyobject:
3200 arg.generate_deletion_code(code)
3201 # else error reported earlier
3203 def annotate(self, code):
3204 for arg in self.args:
3205 arg.annotate(code)
3208 class PassStatNode(StatNode):
3209 # pass statement
3211 child_attrs = []
3213 def analyse_expressions(self, env):
3214 pass
3216 def generate_execution_code(self, code):
3217 pass
3220 class BreakStatNode(StatNode):
3222 child_attrs = []
3224 def analyse_expressions(self, env):
3225 pass
3227 def generate_execution_code(self, code):
3228 if not code.break_label:
3229 error(self.pos, "break statement not inside loop")
3230 else:
3231 #code.putln(
3232 # "goto %s;" %
3233 # code.break_label)
3234 code.put_goto(code.break_label)
3237 class ContinueStatNode(StatNode):
3239 child_attrs = []
3241 def analyse_expressions(self, env):
3242 pass
3244 def generate_execution_code(self, code):
3245 if code.funcstate.in_try_finally:
3246 error(self.pos, "continue statement inside try of try...finally")
3247 elif not code.continue_label:
3248 error(self.pos, "continue statement not inside loop")
3249 else:
3250 code.put_goto(code.continue_label)
3253 class ReturnStatNode(StatNode):
3254 # return statement
3256 # value ExprNode or None
3257 # return_type PyrexType
3258 # temps_in_use [Entry] Temps in use at time of return
3260 child_attrs = ["value"]
3262 def analyse_expressions(self, env):
3263 return_type = env.return_type
3264 self.return_type = return_type
3265 self.temps_in_use = env.temps_in_use()
3266 if not return_type:
3267 error(self.pos, "Return not inside a function body")
3268 return
3269 if self.value:
3270 self.value.analyse_types(env)
3271 if return_type.is_void or return_type.is_returncode:
3272 error(self.value.pos,
3273 "Return with value in void function")
3274 else:
3275 self.value = self.value.coerce_to(env.return_type, env)
3276 self.value.allocate_temps(env)
3277 self.value.release_temp(env)
3278 else:
3279 if (not return_type.is_void
3280 and not return_type.is_pyobject
3281 and not return_type.is_returncode):
3282 error(self.pos, "Return value required")
3283 if return_type.is_pyobject:
3284 self.gil_check(env)
3286 gil_message = "Returning Python object"
3288 def generate_execution_code(self, code):
3289 code.mark_pos(self.pos)
3290 if not self.return_type:
3291 # error reported earlier
3292 return
3293 if self.value:
3294 self.value.generate_evaluation_code(code)
3295 self.value.make_owned_reference(code)
3296 code.putln(
3297 "%s = %s;" % (
3298 Naming.retval_cname,
3299 self.value.result_as(self.return_type)))
3300 self.value.generate_post_assignment_code(code)
3301 self.value.free_temps(code)
3302 else:
3303 if self.return_type.is_pyobject:
3304 code.put_init_to_py_none(Naming.retval_cname, self.return_type)
3305 elif self.return_type.is_returncode:
3306 code.putln(
3307 "%s = %s;" % (
3308 Naming.retval_cname,
3309 self.return_type.default_value))
3310 # free temps the old way
3311 for entry in self.temps_in_use:
3312 code.put_var_decref_clear(entry)
3313 # free temps the new way
3314 for cname, type in code.funcstate.temps_holding_reference():
3315 code.put_decref_clear(cname, type)
3316 #code.putln(
3317 # "goto %s;" %
3318 # code.return_label)
3319 code.put_goto(code.return_label)
3321 def annotate(self, code):
3322 if self.value:
3323 self.value.annotate(code)
3326 class RaiseStatNode(StatNode):
3327 # raise statement
3329 # exc_type ExprNode or None
3330 # exc_value ExprNode or None
3331 # exc_tb ExprNode or None
3333 child_attrs = ["exc_type", "exc_value", "exc_tb"]
3335 def analyse_expressions(self, env):
3336 if self.exc_type:
3337 self.exc_type.analyse_types(env)
3338 self.exc_type = self.exc_type.coerce_to_pyobject(env)
3339 self.exc_type.allocate_temps(env)
3340 if self.exc_value:
3341 self.exc_value.analyse_types(env)
3342 self.exc_value = self.exc_value.coerce_to_pyobject(env)
3343 self.exc_value.allocate_temps(env)
3344 if self.exc_tb:
3345 self.exc_tb.analyse_types(env)
3346 self.exc_tb = self.exc_tb.coerce_to_pyobject(env)
3347 self.exc_tb.allocate_temps(env)
3348 if self.exc_type:
3349 self.exc_type.release_temp(env)
3350 if self.exc_value:
3351 self.exc_value.release_temp(env)
3352 if self.exc_tb:
3353 self.exc_tb.release_temp(env)
3354 env.use_utility_code(raise_utility_code)
3355 env.use_utility_code(restore_exception_utility_code)
3356 self.gil_check(env)
3358 gil_message = "Raising exception"
3360 def generate_execution_code(self, code):
3361 if self.exc_type:
3362 self.exc_type.generate_evaluation_code(code)
3363 type_code = self.exc_type.py_result()
3364 else:
3365 type_code = 0
3366 if self.exc_value:
3367 self.exc_value.generate_evaluation_code(code)
3368 value_code = self.exc_value.py_result()
3369 else:
3370 value_code = "0"
3371 if self.exc_tb:
3372 self.exc_tb.generate_evaluation_code(code)
3373 tb_code = self.exc_tb.py_result()
3374 else:
3375 tb_code = "0"
3376 if self.exc_type or self.exc_value or self.exc_tb:
3377 code.putln(
3378 "__Pyx_Raise(%s, %s, %s);" % (
3379 type_code,
3380 value_code,
3381 tb_code))
3382 else:
3383 code.putln(
3384 "__Pyx_ReRaise();")
3385 for obj in (self.exc_type, self.exc_value, self.exc_tb):
3386 if obj:
3387 obj.generate_disposal_code(code)
3388 obj.free_temps(code)
3389 code.putln(
3390 code.error_goto(self.pos))
3392 def annotate(self, code):
3393 if self.exc_type:
3394 self.exc_type.annotate(code)
3395 if self.exc_value:
3396 self.exc_value.annotate(code)
3397 if self.exc_tb:
3398 self.exc_tb.annotate(code)
3401 class ReraiseStatNode(StatNode):
3403 child_attrs = []
3405 def analyse_expressions(self, env):
3406 self.gil_check(env)
3407 env.use_utility_code(raise_utility_code)
3408 env.use_utility_code(restore_exception_utility_code)
3410 gil_message = "Raising exception"
3412 def generate_execution_code(self, code):
3413 vars = code.funcstate.exc_vars
3414 if vars:
3415 code.putln("__Pyx_Raise(%s, %s, %s);" % tuple(vars))
3416 code.putln(code.error_goto(self.pos))
3417 else:
3418 error(self.pos, "Reraise not inside except clause")
3421 class AssertStatNode(StatNode):
3422 # assert statement
3424 # cond ExprNode
3425 # value ExprNode or None
3427 child_attrs = ["cond", "value"]
3429 def analyse_expressions(self, env):
3430 self.cond = self.cond.analyse_boolean_expression(env)
3431 if self.value:
3432 self.value.analyse_types(env)
3433 self.value = self.value.coerce_to_pyobject(env)
3434 self.value.allocate_temps(env)
3435 self.cond.release_temp(env)
3436 if self.value:
3437 self.value.release_temp(env)
3438 self.gil_check(env)
3439 #env.recycle_pending_temps() # TEMPORARY
3441 gil_message = "Raising exception"
3443 def generate_execution_code(self, code):
3444 code.putln("#ifndef PYREX_WITHOUT_ASSERTIONS")
3445 self.cond.generate_evaluation_code(code)
3446 code.putln(
3447 "if (unlikely(!%s)) {" %
3448 self.cond.result())
3449 if self.value:
3450 self.value.generate_evaluation_code(code)
3451 code.putln(
3452 "PyErr_SetObject(PyExc_AssertionError, %s);" %
3453 self.value.py_result())
3454 self.value.generate_disposal_code(code)
3455 self.value.free_temps(code)
3456 else:
3457 code.putln(
3458 "PyErr_SetNone(PyExc_AssertionError);")
3459 code.putln(
3460 code.error_goto(self.pos))
3461 code.putln(
3462 "}")
3463 self.cond.generate_disposal_code(code)
3464 self.cond.free_temps(code)
3465 code.putln("#endif")
3467 def annotate(self, code):
3468 self.cond.annotate(code)
3469 if self.value:
3470 self.value.annotate(code)
3473 class IfStatNode(StatNode):
3474 # if statement
3476 # if_clauses [IfClauseNode]
3477 # else_clause StatNode or None
3479 child_attrs = ["if_clauses", "else_clause"]
3481 def analyse_control_flow(self, env):
3482 env.start_branching(self.pos)
3483 for if_clause in self.if_clauses:
3484 if_clause.analyse_control_flow(env)
3485 env.next_branch(if_clause.end_pos())
3486 if self.else_clause:
3487 self.else_clause.analyse_control_flow(env)
3488 env.finish_branching(self.end_pos())
3490 def analyse_declarations(self, env):
3491 for if_clause in self.if_clauses:
3492 if_clause.analyse_declarations(env)
3493 if self.else_clause:
3494 self.else_clause.analyse_declarations(env)
3496 def analyse_expressions(self, env):
3497 for if_clause in self.if_clauses:
3498 if_clause.analyse_expressions(env)
3499 if self.else_clause:
3500 self.else_clause.analyse_expressions(env)
3502 def generate_execution_code(self, code):
3503 code.mark_pos(self.pos)
3504 end_label = code.new_label()
3505 for if_clause in self.if_clauses:
3506 if_clause.generate_execution_code(code, end_label)
3507 if self.else_clause:
3508 code.putln("/*else*/ {")
3509 self.else_clause.generate_execution_code(code)
3510 code.putln("}")
3511 code.put_label(end_label)
3513 def annotate(self, code):
3514 for if_clause in self.if_clauses:
3515 if_clause.annotate(code)
3516 if self.else_clause:
3517 self.else_clause.annotate(code)
3520 class IfClauseNode(Node):
3521 # if or elif clause in an if statement
3523 # condition ExprNode
3524 # body StatNode
3526 child_attrs = ["condition", "body"]
3528 def analyse_control_flow(self, env):
3529 self.body.analyse_control_flow(env)
3531 def analyse_declarations(self, env):
3532 self.condition.analyse_declarations(env)
3533 self.body.analyse_declarations(env)
3535 def analyse_expressions(self, env):
3536 self.condition = \
3537 self.condition.analyse_temp_boolean_expression(env)
3538 self.condition.release_temp(env)
3539 self.body.analyse_expressions(env)
3541 def generate_execution_code(self, code, end_label):
3542 self.condition.generate_evaluation_code(code)
3543 code.putln(
3544 "if (%s) {" %
3545 self.condition.result())
3546 self.condition.generate_disposal_code(code)
3547 self.condition.free_temps(code)
3548 self.body.generate_execution_code(code)
3549 #code.putln(
3550 # "goto %s;" %
3551 # end_label)
3552 code.put_goto(end_label)
3553 code.putln("}")
3555 def annotate(self, code):
3556 self.condition.annotate(code)
3557 self.body.annotate(code)
3560 class SwitchCaseNode(StatNode):
3561 # Generated in the optimization of an if-elif-else node
3563 # conditions [ExprNode]
3564 # body StatNode
3566 child_attrs = ['conditions', 'body']
3568 def generate_execution_code(self, code):
3569 for cond in self.conditions:
3570 code.putln("case %s:" % cond.calculate_result_code())
3571 self.body.generate_execution_code(code)
3572 code.putln("break;")
3574 def annotate(self, code):
3575 for cond in self.conditions:
3576 cond.annotate(code)
3577 self.body.annotate(code)
3579 class SwitchStatNode(StatNode):
3580 # Generated in the optimization of an if-elif-else node
3582 # test ExprNode
3583 # cases [SwitchCaseNode]
3584 # else_clause StatNode or None
3586 child_attrs = ['test', 'cases', 'else_clause']
3588 def generate_execution_code(self, code):
3589 code.putln("switch (%s) {" % self.test.calculate_result_code())
3590 for case in self.cases:
3591 case.generate_execution_code(code)
3592 if self.else_clause is not None:
3593 code.putln("default:")
3594 self.else_clause.generate_execution_code(code)
3595 code.putln("break;")
3596 code.putln("}")
3598 def annotate(self, code):
3599 self.test.annotate(code)
3600 for case in self.cases:
3601 case.annotate(code)
3602 if self.else_clause is not None:
3603 self.else_clause.annotate(code)
3605 class LoopNode:
3607 def analyse_control_flow(self, env):
3608 env.start_branching(self.pos)
3609 self.body.analyse_control_flow(env)
3610 env.next_branch(self.body.end_pos())
3611 if self.else_clause:
3612 self.else_clause.analyse_control_flow(env)
3613 env.finish_branching(self.end_pos())
3616 class WhileStatNode(LoopNode, StatNode):
3617 # while statement
3619 # condition ExprNode
3620 # body StatNode
3621 # else_clause StatNode
3623 child_attrs = ["condition", "body", "else_clause"]
3625 def analyse_declarations(self, env):
3626 self.body.analyse_declarations(env)
3627 if self.else_clause:
3628 self.else_clause.analyse_declarations(env)
3630 def analyse_expressions(self, env):
3631 self.condition = \
3632 self.condition.analyse_temp_boolean_expression(env)
3633 self.condition.release_temp(env)
3634 #env.recycle_pending_temps() # TEMPORARY
3635 self.body.analyse_expressions(env)
3636 if self.else_clause:
3637 self.else_clause.analyse_expressions(env)
3639 def generate_execution_code(self, code):
3640 old_loop_labels = code.new_loop_labels()
3641 code.putln(
3642 "while (1) {")
3643 self.condition.generate_evaluation_code(code)
3644 self.condition.generate_disposal_code(code)
3645 code.putln(
3646 "if (!%s) break;" %
3647 self.condition.result())
3648 self.condition.free_temps(code)
3649 self.body.generate_execution_code(code)
3650 code.put_label(code.continue_label)
3651 code.putln("}")
3652 break_label = code.break_label
3653 code.set_loop_labels(old_loop_labels)
3654 if self.else_clause:
3655 code.putln("/*else*/ {")
3656 self.else_clause.generate_execution_code(code)
3657 code.putln("}")
3658 code.put_label(break_label)
3660 def annotate(self, code):
3661 self.condition.annotate(code)
3662 self.body.annotate(code)
3663 if self.else_clause:
3664 self.else_clause.annotate(code)
3667 def ForStatNode(pos, **kw):
3668 if kw.has_key('iterator'):
3669 return ForInStatNode(pos, **kw)
3670 else:
3671 return ForFromStatNode(pos, **kw)
3673 class ForInStatNode(LoopNode, StatNode):
3674 # for statement
3676 # target ExprNode
3677 # iterator IteratorNode
3678 # body StatNode
3679 # else_clause StatNode
3680 # item NextNode used internally
3682 child_attrs = ["target", "iterator", "body", "else_clause"]
3683 item = None
3685 def analyse_declarations(self, env):
3686 self.target.analyse_target_declaration(env)
3687 self.body.analyse_declarations(env)
3688 if self.else_clause:
3689 self.else_clause.analyse_declarations(env)
3691 def analyse_range_step(self, args):
3692 import ExprNodes
3693 # The direction must be determined at compile time to set relations.
3694 # Otherwise, return False.
3695 if len(args) < 3:
3696 self.step = ExprNodes.IntNode(pos = args[0].pos, value='1')
3697 self.relation1 = '<='
3698 self.relation2 = '<'
3699 return True
3700 else:
3701 step = args[2]
3702 if isinstance(step, ExprNodes.UnaryMinusNode) and isinstance(step.operand, ExprNodes.IntNode):
3703 step = ExprNodes.IntNode(pos = step.pos, value=str(-int(step.operand.value, 0)))
3704 if isinstance(step, ExprNodes.IntNode):
3705 step_value = int(step.value, 0)
3706 if step_value > 0:
3707 self.step = step
3708 self.relation1 = '<='
3709 self.relation2 = '<'
3710 return True
3711 elif step_value < 0:
3712 self.step = ExprNodes.IntNode(pos = step.pos, value=str(-step_value))
3713 self.relation1 = '>='
3714 self.relation2 = '>'
3715 return True
3716 return False
3719 def analyse_expressions(self, env):
3720 import ExprNodes
3721 self.target.analyse_target_types(env)
3722 if False: # Options.convert_range and self.target.type.is_int:
3723 sequence = self.iterator.sequence
3724 if isinstance(sequence, ExprNodes.SimpleCallNode) \
3725 and sequence.self is None \
3726 and isinstance(sequence.function, ExprNodes.NameNode) \
3727 and (sequence.function.name == 'range' or sequence.function.name == 'xrange'):
3728 args = sequence.args
3729 # Make sure we can determine direction from step
3730 if self.analyse_range_step(args):
3731 # Mutate to ForFrom loop type
3732 self.__class__ = ForFromStatNode
3733 if len(args) == 1:
3734 self.bound1 = ExprNodes.IntNode(pos = sequence.pos, value='0')
3735 self.bound2 = args[0]
3736 else:
3737 self.bound1 = args[0]
3738 self.bound2 = args[1]
3739 ForFromStatNode.analyse_expressions(self, env)
3740 return
3742 self.iterator.analyse_expressions(env)
3743 self.item = ExprNodes.NextNode(self.iterator, env)
3744 self.item = self.item.coerce_to(self.target.type, env)
3745 self.item.allocate_temps(env)
3746 self.target.allocate_target_temps(env, self.item)
3747 #self.item.release_temp(env)
3748 #self.target.release_target_temp(env)
3749 self.body.analyse_expressions(env)
3750 if self.else_clause:
3751 self.else_clause.analyse_expressions(env)
3752 self.iterator.release_temp(env)
3754 def generate_execution_code(self, code):
3755 old_loop_labels = code.new_loop_labels()
3756 self.iterator.allocate_counter_temp(code)
3757 self.iterator.generate_evaluation_code(code)
3758 code.putln(
3759 "for (;;) {")
3760 self.item.generate_evaluation_code(code)
3761 self.target.generate_assignment_code(self.item, code)
3762 self.body.generate_execution_code(code)
3763 code.put_label(code.continue_label)
3764 code.putln(
3765 "}")
3766 break_label = code.break_label
3767 code.set_loop_labels(old_loop_labels)
3768 if self.else_clause:
3769 code.putln("/*else*/ {")
3770 self.else_clause.generate_execution_code(code)
3771 code.putln("}")
3772 code.put_label(break_label)
3773 self.iterator.release_counter_temp(code)
3774 self.iterator.generate_disposal_code(code)
3775 self.iterator.free_temps(code)
3777 def annotate(self, code):
3778 self.target.annotate(code)
3779 self.iterator.annotate(code)
3780 self.body.annotate(code)
3781 if self.else_clause:
3782 self.else_clause.annotate(code)
3783 self.item.annotate(code)
3786 class ForFromStatNode(LoopNode, StatNode):
3787 # for name from expr rel name rel expr
3789 # target NameNode
3790 # bound1 ExprNode
3791 # relation1 string
3792 # relation2 string
3793 # bound2 ExprNode
3794 # step ExprNode or None
3795 # body StatNode
3796 # else_clause StatNode or None
3798 # Used internally:
3800 # is_py_target bool
3801 # loopvar_name string
3802 # py_loopvar_node PyTempNode or None
3803 child_attrs = ["target", "bound1", "bound2", "step", "body", "else_clause"]
3805 is_py_target = False
3806 loopvar_name = None
3807 py_loopvar_node = None
3809 def analyse_declarations(self, env):
3810 self.target.analyse_target_declaration(env)
3811 self.body.analyse_declarations(env)
3812 if self.else_clause:
3813 self.else_clause.analyse_declarations(env)
3815 def analyse_expressions(self, env):
3816 import ExprNodes
3817 self.target.analyse_target_types(env)
3818 self.bound1.analyse_types(env)
3819 self.bound2.analyse_types(env)
3820 if self.target.type.is_numeric:
3821 self.bound1 = self.bound1.coerce_to(self.target.type, env)
3822 self.bound2 = self.bound2.coerce_to(self.target.type, env)
3823 else:
3824 self.bound1 = self.bound1.coerce_to_integer(env)
3825 self.bound2 = self.bound2.coerce_to_integer(env)
3826 if self.step is not None:
3827 if isinstance(self.step, ExprNodes.UnaryMinusNode):
3828 warning(self.step.pos, "Probable infinite loop in for-from-by statment. Consider switching the directions of the relations.", 2)
3829 self.step.analyse_types(env)
3830 self.step = self.step.coerce_to_integer(env)
3831 if not (self.bound2.is_name or self.bound2.is_literal):
3832 self.bound2 = self.bound2.coerce_to_temp(env)
3833 target_type = self.target.type
3834 if not (target_type.is_pyobject or target_type.is_numeric):
3835 error(self.target.pos,
3836 "Integer for-loop variable must be of type int or Python object")
3837 #if not (target_type.is_pyobject
3838 # or target_type.assignable_from(PyrexTypes.c_int_type)):
3839 # error(self.target.pos,
3840 # "Cannot assign integer to variable of type '%s'" % target_type)
3841 if target_type.is_numeric:
3842 self.is_py_target = 0
3843 if isinstance(self.target, ExprNodes.IndexNode) and self.target.is_buffer_access:
3844 raise error(self.pos, "Buffer indexing not allowed as for loop target.")
3845 self.loopvar_name = self.target.entry.cname
3846 self.py_loopvar_node = None
3847 else:
3848 self.is_py_target = 1
3849 c_loopvar_node = ExprNodes.TempNode(self.pos,
3850 PyrexTypes.c_long_type, env)
3851 c_loopvar_node.allocate_temps(env)
3852 self.loopvar_name = c_loopvar_node.result()
3853 self.py_loopvar_node = \
3854 ExprNodes.CloneNode(c_loopvar_node).coerce_to_pyobject(env)
3855 self.bound1.allocate_temps(env)
3856 self.bound2.allocate_temps(env)
3857 if self.step is not None:
3858 self.step.allocate_temps(env)
3859 if self.is_py_target:
3860 self.py_loopvar_node.allocate_temps(env)
3861 self.target.allocate_target_temps(env, self.py_loopvar_node)
3862 #self.target.release_target_temp(env)
3863 #self.py_loopvar_node.release_temp(env)
3864 self.body.analyse_expressions(env)
3865 if self.is_py_target:
3866 c_loopvar_node.release_temp(env)
3867 if self.else_clause:
3868 self.else_clause.analyse_expressions(env)
3869 self.bound1.release_temp(env)
3870 self.bound2.release_temp(env)
3871 if self.step is not None:
3872 self.step.release_temp(env)
3874 def reanalyse_c_loop(self, env):
3875 # only make sure all subnodes have an integer type
3876 self.bound1 = self.bound1.coerce_to_integer(env)
3877 self.bound2 = self.bound2.coerce_to_integer(env)
3878 if self.step is not None:
3879 self.step = self.step.coerce_to_integer(env)
3881 def generate_execution_code(self, code):
3882 old_loop_labels = code.new_loop_labels()
3883 self.bound1.generate_evaluation_code(code)
3884 self.bound2.generate_evaluation_code(code)
3885 offset, incop = self.relation_table[self.relation1]
3886 if self.step is not None:
3887 self.step.generate_evaluation_code(code)
3888 incop = "%s=%s" % (incop[0], self.step.result())
3889 code.putln(
3890 "for (%s = %s%s; %s %s %s; %s%s) {" % (
3891 self.loopvar_name,
3892 self.bound1.result(), offset,
3893 self.loopvar_name, self.relation2, self.bound2.result(),
3894 self.loopvar_name, incop))
3895 if self.py_loopvar_node:
3896 self.py_loopvar_node.generate_evaluation_code(code)
3897 self.target.generate_assignment_code(self.py_loopvar_node, code)
3898 self.body.generate_execution_code(code)
3899 code.put_label(code.continue_label)
3900 code.putln("}")
3901 break_label = code.break_label
3902 code.set_loop_labels(old_loop_labels)
3903 if self.else_clause:
3904 code.putln("/*else*/ {")
3905 self.else_clause.generate_execution_code(code)
3906 code.putln("}")
3907 code.put_label(break_label)
3908 self.bound1.generate_disposal_code(code)
3909 self.bound1.free_temps(code)
3910 self.bound2.generate_disposal_code(code)
3911 self.bound2.free_temps(code)
3912 if self.step is not None:
3913 self.step.generate_disposal_code(code)
3914 self.step.free_temps(code)
3916 relation_table = {
3917 # {relop : (initial offset, increment op)}
3918 '<=': ("", "++"),
3919 '<' : ("+1", "++"),
3920 '>=': ("", "--"),
3921 '>' : ("-1", "--")
3924 def annotate(self, code):
3925 self.target.annotate(code)
3926 self.bound1.annotate(code)
3927 self.bound2.annotate(code)
3928 if self.step:
3929 self.bound2.annotate(code)
3930 self.body.annotate(code)
3931 if self.else_clause:
3932 self.else_clause.annotate(code)
3935 class WithStatNode(StatNode):
3936 """
3937 Represents a Python with statement.
3939 This is only used at parse tree level; and is not present in
3940 analysis or generation phases.
3941 """
3942 # manager The with statement manager object
3943 # target Node (lhs expression)
3944 # body StatNode
3945 child_attrs = ["manager", "target", "body"]
3947 class TryExceptStatNode(StatNode):
3948 # try .. except statement
3950 # body StatNode
3951 # except_clauses [ExceptClauseNode]
3952 # else_clause StatNode or None
3953 # cleanup_list [Entry] temps to clean up on error
3955 child_attrs = ["body", "except_clauses", "else_clause"]
3957 def analyse_control_flow(self, env):
3958 env.start_branching(self.pos)
3959 self.body.analyse_control_flow(env)
3960 successful_try = env.control_flow # grab this for later
3961 env.next_branch(self.body.end_pos())
3962 env.finish_branching(self.body.end_pos())
3964 env.start_branching(self.except_clauses[0].pos)
3965 for except_clause in self.except_clauses:
3966 except_clause.analyse_control_flow(env)
3967 env.next_branch(except_clause.end_pos())
3969 # the else cause it executed only when the try clause finishes
3970 env.control_flow.incoming = successful_try
3971 if self.else_clause:
3972 self.else_clause.analyse_control_flow(env)
3973 env.finish_branching(self.end_pos())
3975 def analyse_declarations(self, env):
3976 self.body.analyse_declarations(env)
3977 for except_clause in self.except_clauses:
3978 except_clause.analyse_declarations(env)
3979 if self.else_clause:
3980 self.else_clause.analyse_declarations(env)
3981 self.gil_check(env)
3982 env.use_utility_code(reset_exception_utility_code)
3984 def analyse_expressions(self, env):
3985 self.body.analyse_expressions(env)
3986 self.cleanup_list = env.free_temp_entries[:]
3987 default_clause_seen = 0
3988 for except_clause in self.except_clauses:
3989 except_clause.analyse_expressions(env)
3990 if default_clause_seen:
3991 error(except_clause.pos, "default 'except:' must be last")
3992 if not except_clause.pattern:
3993 default_clause_seen = 1
3994 self.has_default_clause = default_clause_seen
3995 if self.else_clause:
3996 self.else_clause.analyse_expressions(env)
3997 self.gil_check(env)
3999 gil_message = "Try-except statement"
4001 def generate_execution_code(self, code):
4002 old_return_label = code.return_label
4003 old_error_label = code.new_error_label()
4004 our_error_label = code.error_label
4005 except_end_label = code.new_label('exception_handled')
4006 except_error_label = code.new_label('except_error')
4007 except_return_label = code.new_label('except_return')
4008 try_end_label = code.new_label('try')
4010 code.putln("{")
4011 code.putln("PyObject %s;" %
4012 ', '.join(['*%s' % var for var in Naming.exc_save_vars]))
4013 code.putln("__Pyx_ExceptionSave(%s);" %
4014 ', '.join(['&%s' % var for var in Naming.exc_save_vars]))
4015 code.putln(
4016 "/*try:*/ {")
4017 self.body.generate_execution_code(code)
4018 code.putln(
4019 "}")
4020 code.error_label = except_error_label
4021 code.return_label = except_return_label
4022 if self.else_clause:
4023 code.putln(
4024 "/*else:*/ {")
4025 self.else_clause.generate_execution_code(code)
4026 code.putln(
4027 "}")
4028 for var in Naming.exc_save_vars:
4029 code.put_xdecref_clear(var, py_object_type)
4030 code.put_goto(try_end_label)
4031 code.put_label(our_error_label)
4032 code.put_var_xdecrefs_clear(self.cleanup_list)
4033 for except_clause in self.except_clauses:
4034 except_clause.generate_handling_code(code, except_end_label)
4036 error_label_used = code.label_used(except_error_label)
4037 if error_label_used or not self.has_default_clause:
4038 if error_label_used:
4039 code.put_label(except_error_label)
4040 for var in Naming.exc_save_vars:
4041 code.put_xdecref(var, py_object_type)
4042 code.put_goto(old_error_label)
4044 if code.label_used(except_return_label):
4045 code.put_label(except_return_label)
4046 code.putln("__Pyx_ExceptionReset(%s);" %
4047 ', '.join(Naming.exc_save_vars))
4048 code.put_goto(old_return_label)
4050 if code.label_used(except_end_label):
4051 code.put_label(except_end_label)
4052 code.putln("__Pyx_ExceptionReset(%s);" %
4053 ', '.join(Naming.exc_save_vars))
4054 code.put_label(try_end_label)
4055 code.putln("}")
4057 code.return_label = old_return_label
4058 code.error_label = old_error_label
4060 def annotate(self, code):
4061 self.body.annotate(code)
4062 for except_node in self.except_clauses:
4063 except_node.annotate(code)
4064 if self.else_clause:
4065 self.else_clause.annotate(code)
4068 class ExceptClauseNode(Node):
4069 # Part of try ... except statement.
4071 # pattern ExprNode
4072 # target ExprNode or None
4073 # body StatNode
4074 # excinfo_target NameNode or None optional target for exception info
4075 # match_flag string result of exception match
4076 # exc_value ExcValueNode used internally
4077 # function_name string qualified name of enclosing function
4078 # exc_vars (string * 3) local exception variables
4080 # excinfo_target is never set by the parser, but can be set by a transform
4081 # in order to extract more extensive information about the exception as a
4082 # sys.exc_info()-style tuple into a target variable
4084 child_attrs = ["pattern", "target", "body", "exc_value", "excinfo_target"]
4086 exc_value = None
4087 excinfo_target = None
4089 def analyse_declarations(self, env):
4090 if self.target:
4091 self.target.analyse_target_declaration(env)
4092 if self.excinfo_target is not None:
4093 self.excinfo_target.analyse_target_declaration(env)
4094 self.body.analyse_declarations(env)
4096 def analyse_expressions(self, env):
4097 import ExprNodes
4098 genv = env.global_scope()
4099 self.function_name = env.qualified_name
4100 if self.pattern:
4101 self.pattern.analyse_expressions(env)
4102 self.pattern = self.pattern.coerce_to_pyobject(env)
4103 self.match_flag = env.allocate_temp(PyrexTypes.c_int_type)
4104 self.pattern.release_temp(env)
4105 env.release_temp(self.match_flag)
4106 self.exc_vars = [env.allocate_temp(py_object_type) for i in xrange(3)]
4107 if self.target:
4108 self.exc_value = ExprNodes.ExcValueNode(self.pos, env, self.exc_vars[1])
4109 self.exc_value.allocate_temps(env)
4110 self.target.analyse_target_expression(env, self.exc_value)
4111 if self.excinfo_target is not None:
4112 import ExprNodes
4113 self.excinfo_tuple = ExprNodes.TupleNode(pos=self.pos, args=[
4114 ExprNodes.ExcValueNode(pos=self.pos, env=env, var=self.exc_vars[0]),
4115 ExprNodes.ExcValueNode(pos=self.pos, env=env, var=self.exc_vars[1]),
4116 ExprNodes.ExcValueNode(pos=self.pos, env=env, var=self.exc_vars[2])
4117 ])
4118 self.excinfo_tuple.analyse_expressions(env)
4119 self.excinfo_tuple.allocate_temps(env)
4120 self.excinfo_target.analyse_target_expression(env, self.excinfo_tuple)
4122 self.body.analyse_expressions(env)
4123 for var in self.exc_vars:
4124 env.release_temp(var)
4125 env.use_utility_code(get_exception_utility_code)
4126 env.use_utility_code(restore_exception_utility_code)
4128 def generate_handling_code(self, code, end_label):
4129 code.mark_pos(self.pos)
4130 if self.pattern:
4131 self.pattern.generate_evaluation_code(code)
4132 code.putln(
4133 "%s = PyErr_ExceptionMatches(%s);" % (
4134 self.match_flag,
4135 self.pattern.py_result()))
4136 self.pattern.generate_disposal_code(code)
4137 self.pattern.free_temps(code)
4138 code.putln(
4139 "if (%s) {" %
4140 self.match_flag)
4141 else:
4142 code.putln("/*except:*/ {")
4143 code.putln('__Pyx_AddTraceback("%s");' % self.function_name)
4144 # We always have to fetch the exception value even if
4145 # there is no target, because this also normalises the
4146 # exception and stores it in the thread state.
4147 exc_args = "&%s, &%s, &%s" % tuple(self.exc_vars)
4148 code.putln("if (__Pyx_GetException(%s) < 0) %s" % (exc_args,
4149 code.error_goto(self.pos)))
4150 if self.target:
4151 self.exc_value.generate_evaluation_code(code)
4152 self.target.generate_assignment_code(self.exc_value, code)
4153 if self.excinfo_target is not None:
4154 self.excinfo_tuple.generate_evaluation_code(code)
4155 self.excinfo_target.generate_assignment_code(self.excinfo_tuple, code)
4157 old_exc_vars = code.funcstate.exc_vars
4158 code.funcstate.exc_vars = self.exc_vars
4159 self.body.generate_execution_code(code)
4160 code.funcstate.exc_vars = old_exc_vars
4161 for var in self.exc_vars:
4162 code.putln("Py_DECREF(%s); %s = 0;" % (var, var))
4163 code.put_goto(end_label)
4164 code.putln(
4165 "}")
4167 def annotate(self, code):
4168 if self.pattern:
4169 self.pattern.annotate(code)
4170 if self.target:
4171 self.target.annotate(code)
4172 self.body.annotate(code)
4175 class TryFinallyStatNode(StatNode):
4176 # try ... finally statement
4178 # body StatNode
4179 # finally_clause StatNode
4181 # cleanup_list [Entry] temps to clean up on error
4183 # The plan is that we funnel all continue, break
4184 # return and error gotos into the beginning of the
4185 # finally block, setting a variable to remember which
4186 # one we're doing. At the end of the finally block, we
4187 # switch on the variable to figure out where to go.
4188 # In addition, if we're doing an error, we save the
4189 # exception on entry to the finally block and restore
4190 # it on exit.
4192 child_attrs = ["body", "finally_clause"]
4194 preserve_exception = 1
4196 disallow_continue_in_try_finally = 0
4197 # There doesn't seem to be any point in disallowing
4198 # continue in the try block, since we have no problem
4199 # handling it.
4201 def create_analysed(pos, env, body, finally_clause):
4202 node = TryFinallyStatNode(pos, body=body, finally_clause=finally_clause)
4203 node.cleanup_list = []
4204 return node
4205 create_analysed = staticmethod(create_analysed)
4207 def analyse_control_flow(self, env):
4208 env.start_branching(self.pos)
4209 self.body.analyse_control_flow(env)
4210 env.next_branch(self.body.end_pos())
4211 env.finish_branching(self.body.end_pos())
4212 self.finally_clause.analyse_control_flow(env)
4214 def analyse_declarations(self, env):
4215 self.body.analyse_declarations(env)
4216 self.finally_clause.analyse_declarations(env)
4218 def analyse_expressions(self, env):
4219 self.body.analyse_expressions(env)
4220 self.cleanup_list = env.free_temp_entries[:]
4221 self.finally_clause.analyse_expressions(env)
4222 self.gil_check(env)
4224 gil_message = "Try-finally statement"
4226 def generate_execution_code(self, code):
4227 old_error_label = code.error_label
4228 old_labels = code.all_new_labels()
4229 new_labels = code.get_all_labels()
4230 new_error_label = code.error_label
4231 catch_label = code.new_label()
4232 code.putln(
4233 "/*try:*/ {")
4234 if self.disallow_continue_in_try_finally:
4235 was_in_try_finally = code.funcstate.in_try_finally
4236 code.funcstate.in_try_finally = 1
4237 self.body.generate_execution_code(code)
4238 if self.disallow_continue_in_try_finally:
4239 code.funcstate.in_try_finally = was_in_try_finally
4240 code.putln(
4241 "}")
4242 code.putln(
4243 "/*finally:*/ {")
4244 cases_used = []
4245 error_label_used = 0
4246 for i, new_label in enumerate(new_labels):
4247 if new_label in code.labels_used:
4248 cases_used.append(i)
4249 if new_label == new_error_label:
4250 error_label_used = 1
4251 error_label_case = i
4252 if cases_used:
4253 code.putln(
4254 "int __pyx_why;")
4255 if error_label_used and self.preserve_exception:
4256 code.putln(
4257 "PyObject *%s, *%s, *%s;" % Naming.exc_vars)
4258 code.putln(
4259 "int %s;" % Naming.exc_lineno_name)
4260 exc_var_init_zero = ''.join(["%s = 0; " % var for var in Naming.exc_vars])
4261 exc_var_init_zero += '%s = 0;' % Naming.exc_lineno_name
4262 code.putln(exc_var_init_zero)
4263 else:
4264 exc_var_init_zero = None
4265 code.use_label(catch_label)
4266 code.putln(
4267 "__pyx_why = 0; goto %s;" % catch_label)
4268 for i in cases_used:
4269 new_label = new_labels[i]
4270 #if new_label and new_label != "<try>":
4271 if new_label == new_error_label and self.preserve_exception:
4272 self.put_error_catcher(code,
4273 new_error_label, i+1, catch_label)
4274 else:
4275 code.put('%s: ' % new_label)
4276 if exc_var_init_zero:
4277 code.putln(exc_var_init_zero)
4278 code.putln("__pyx_why = %s; goto %s;" % (
4279 i+1,
4280 catch_label))
4281 code.put_label(catch_label)
4282 code.set_all_labels(old_labels)
4283 if error_label_used:
4284 code.new_error_label()
4285 finally_error_label = code.error_label
4286 self.finally_clause.generate_execution_code(code)
4287 if error_label_used:
4288 if finally_error_label in code.labels_used and self.preserve_exception:
4289 over_label = code.new_label()
4290 code.put_goto(over_label);
4291 code.put_label(finally_error_label)
4292 code.putln("if (__pyx_why == %d) {" % (error_label_case + 1))
4293 for var in Naming.exc_vars:
4294 code.putln("Py_XDECREF(%s);" % var)
4295 code.putln("}")
4296 code.put_goto(old_error_label)
4297 code.put_label(over_label)
4298 code.error_label = old_error_label
4299 if cases_used:
4300 code.putln(
4301 "switch (__pyx_why) {")
4302 for i in cases_used:
4303 old_label = old_labels[i]
4304 if old_label == old_error_label and self.preserve_exception:
4305 self.put_error_uncatcher(code, i+1, old_error_label)
4306 else:
4307 code.use_label(old_label)
4308 code.putln(
4309 "case %s: goto %s;" % (
4310 i+1,
4311 old_label))
4312 code.putln(
4313 "}")
4314 code.putln(
4315 "}")
4317 def put_error_catcher(self, code, error_label, i, catch_label):
4318 code.globalstate.use_utility_code(restore_exception_utility_code)
4319 code.putln(
4320 "%s: {" %
4321 error_label)
4322 code.putln(
4323 "__pyx_why = %s;" %
4324 i)
4325 code.put_var_xdecrefs_clear(self.cleanup_list)
4326 code.putln(
4327 "__Pyx_ErrFetch(&%s, &%s, &%s);" %
4328 Naming.exc_vars)
4329 code.putln(
4330 "%s = %s;" % (
4331 Naming.exc_lineno_name, Naming.lineno_cname))
4332 #code.putln(
4333 # "goto %s;" %
4334 # catch_label)
4335 code.put_goto(catch_label)
4336 code.putln(
4337 "}")
4339 def put_error_uncatcher(self, code, i, error_label):
4340 code.globalstate.use_utility_code(restore_exception_utility_code)
4341 code.putln(
4342 "case %s: {" %
4343 i)
4344 code.putln(
4345 "__Pyx_ErrRestore(%s, %s, %s);" %
4346 Naming.exc_vars)
4347 code.putln(
4348 "%s = %s;" % (
4349 Naming.lineno_cname, Naming.exc_lineno_name))
4350 for var in Naming.exc_vars:
4351 code.putln(
4352 "%s = 0;" %
4353 var)
4354 code.put_goto(error_label)
4355 code.putln(
4356 "}")
4358 def annotate(self, code):
4359 self.body.annotate(code)
4360 self.finally_clause.annotate(code)
4363 class GILStatNode(TryFinallyStatNode):
4364 # 'with gil' or 'with nogil' statement
4366 # state string 'gil' or 'nogil'
4368 child_attrs = []
4370 preserve_exception = 0
4372 def __init__(self, pos, state, body):
4373 self.state = state
4374 TryFinallyStatNode.__init__(self, pos,
4375 body = body,
4376 finally_clause = GILExitNode(pos, state = state))
4378 def analyse_expressions(self, env):
4379 was_nogil = env.nogil
4380 env.nogil = 1
4381 TryFinallyStatNode.analyse_expressions(self, env)
4382 env.nogil = was_nogil
4384 def gil_check(self, env):
4385 pass
4387 def generate_execution_code(self, code):
4388 code.putln("/*with %s:*/ {" % self.state)
4389 if self.state == 'gil':
4390 code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
4391 else:
4392 code.putln("PyThreadState *_save;")
4393 code.putln("Py_UNBLOCK_THREADS")
4394 TryFinallyStatNode.generate_execution_code(self, code)
4395 code.putln("}")
4398 class GILExitNode(StatNode):
4399 # Used as the 'finally' block in a GILStatNode
4401 # state string 'gil' or 'nogil'
4403 child_attrs = []
4405 def analyse_expressions(self, env):
4406 pass
4408 def generate_execution_code(self, code):
4409 if self.state == 'gil':
4410 code.putln("PyGILState_Release();")
4411 else:
4412 code.putln("Py_BLOCK_THREADS")
4415 class CImportStatNode(StatNode):
4416 # cimport statement
4418 # module_name string Qualified name of module being imported
4419 # as_name string or None Name specified in "as" clause, if any
4421 child_attrs = []
4423 def analyse_declarations(self, env):
4424 if not env.is_module_scope:
4425 error(self.pos, "cimport only allowed at module level")
4426 return
4427 module_scope = env.find_module(self.module_name, self.pos)
4428 if "." in self.module_name:
4429 names = [EncodedString(name) for name in self.module_name.split(".")]
4430 top_name = names[0]
4431 top_module_scope = env.context.find_submodule(top_name)
4432 module_scope = top_module_scope
4433 for name in names[1:]:
4434 submodule_scope = module_scope.find_submodule(name)
4435 module_scope.declare_module(name, submodule_scope, self.pos)
4436 module_scope = submodule_scope
4437 if self.as_name:
4438 env.declare_module(self.as_name, module_scope, self.pos)
4439 else:
4440 env.declare_module(top_name, top_module_scope, self.pos)
4441 else:
4442 name = self.as_name or self.module_name
4443 env.declare_module(name, module_scope, self.pos)
4445 def analyse_expressions(self, env):
4446 pass
4448 def generate_execution_code(self, code):
4449 pass
4452 class FromCImportStatNode(StatNode):
4453 # from ... cimport statement
4455 # module_name string Qualified name of module
4456 # imported_names [(pos, name, as_name, kind)] Names to be imported
4458 child_attrs = []
4460 def analyse_declarations(self, env):
4461 if not env.is_module_scope:
4462 error(self.pos, "cimport only allowed at module level")
4463 return
4464 module_scope = env.find_module(self.module_name, self.pos)
4465 env.add_imported_module(module_scope)
4466 for pos, name, as_name, kind in self.imported_names:
4467 if name == "*":
4468 for local_name, entry in module_scope.entries.items():
4469 env.add_imported_entry(local_name, entry, pos)
4470 else:
4471 entry = module_scope.lookup(name)
4472 if entry:
4473 if kind and not self.declaration_matches(entry, kind):
4474 entry.redeclared(pos)
4475 else:
4476 if kind == 'struct' or kind == 'union':
4477 entry = module_scope.declare_struct_or_union(name,
4478 kind = kind, scope = None, typedef_flag = 0, pos = pos)
4479 elif kind == 'class':
4480 entry = module_scope.declare_c_class(name, pos = pos,
4481 module_name = self.module_name)
4482 else:
4483 error(pos, "Name '%s' not declared in module '%s'"
4484 % (name, self.module_name))
4486 if entry:
4487 local_name = as_name or name
4488 env.add_imported_entry(local_name, entry, pos)
4490 def declaration_matches(self, entry, kind):
4491 if not entry.is_type:
4492 return 0
4493 type = entry.type
4494 if kind == 'class':
4495 if not type.is_extension_type:
4496 return 0
4497 else:
4498 if not type.is_struct_or_union:
4499 return 0
4500 if kind <> type.kind:
4501 return 0
4502 return 1
4504 def analyse_expressions(self, env):
4505 pass
4507 def generate_execution_code(self, code):
4508 pass
4511 class FromImportStatNode(StatNode):
4512 # from ... import statement
4514 # module ImportNode
4515 # items [(string, NameNode)]
4516 # interned_items [(string, NameNode)]
4517 # item PyTempNode used internally
4518 # import_star boolean used internally
4520 child_attrs = ["module"]
4521 import_star = 0
4523 def analyse_declarations(self, env):
4524 for name, target in self.items:
4525 if name == "*":
4526 if not env.is_module_scope:
4527 error(self.pos, "import * only allowed at module level")
4528 return
4529 env.has_import_star = 1
4530 self.import_star = 1
4531 else:
4532 target.analyse_target_declaration(env)
4534 def analyse_expressions(self, env):
4535 import ExprNodes
4536 self.module.analyse_expressions(env)
4537 self.item = ExprNodes.PyTempNode(self.pos, env)
4538 self.item.allocate_temp(env)
4539 self.interned_items = []
4540 for name, target in self.items:
4541 if name == '*':
4542 for _, entry in env.entries.items():
4543 if not entry.is_type and entry.type.is_extension_type:
4544 env.use_utility_code(ExprNodes.type_test_utility_code)
4545 break
4546 else:
4547 entry = env.lookup(target.name)
4548 if entry.is_type and entry.type.name == name and entry.type.module_name == self.module.module_name.value:
4549 continue # already cimported
4550 self.interned_items.append(
4551 (env.intern_identifier(name), target))
4552 target.analyse_target_expression(env, None)
4553 #target.release_target_temp(env) # was release_temp ?!?
4554 self.module.release_temp(env)
4555 self.item.release_temp(env)
4557 def generate_execution_code(self, code):
4558 self.module.generate_evaluation_code(code)
4559 if self.import_star:
4560 code.putln(
4561 'if (%s(%s) < 0) %s;' % (
4562 Naming.import_star,
4563 self.module.py_result(),
4564 code.error_goto(self.pos)))
4565 for cname, target in self.interned_items:
4566 code.putln(
4567 '%s = PyObject_GetAttr(%s, %s); %s' % (
4568 self.item.result(),
4569 self.module.py_result(),
4570 cname,
4571 code.error_goto_if_null(self.item.result(), self.pos)))
4572 target.generate_assignment_code(self.item, code)
4573 self.module.generate_disposal_code(code)
4574 self.module.free_temps(code)
4578 #------------------------------------------------------------------------------------
4580 # Runtime support code
4582 #------------------------------------------------------------------------------------
4584 utility_function_predeclarations = \
4585 """
4586 #ifdef __GNUC__
4587 #define INLINE __inline__
4588 #elif _WIN32
4589 #define INLINE __inline
4590 #else
4591 #define INLINE
4592 #endif
4594 typedef struct {PyObject **p; char *s; long n; char is_unicode; char intern; char is_identifier;} __Pyx_StringTabEntry; /*proto*/
4596 """ + """
4598 static int %(skip_dispatch_cname)s = 0;
4600 """ % { 'skip_dispatch_cname': Naming.skip_dispatch_cname }
4602 if Options.gcc_branch_hints:
4603 branch_prediction_macros = \
4604 """
4605 #ifdef __GNUC__
4606 /* Test for GCC > 2.95 */
4607 #if __GNUC__ > 2 || \
4608 (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))
4609 #define likely(x) __builtin_expect(!!(x), 1)
4610 #define unlikely(x) __builtin_expect(!!(x), 0)
4611 #else /* __GNUC__ > 2 ... */
4612 #define likely(x) (x)
4613 #define unlikely(x) (x)
4614 #endif /* __GNUC__ > 2 ... */
4615 #else /* __GNUC__ */
4616 #define likely(x) (x)
4617 #define unlikely(x) (x)
4618 #endif /* __GNUC__ */
4619 """
4620 else:
4621 branch_prediction_macros = \
4622 """
4623 #define likely(x) (x)
4624 #define unlikely(x) (x)
4625 """
4627 #get_name_predeclaration = \
4628 #"static PyObject *__Pyx_GetName(PyObject *dict, char *name); /*proto*/"
4630 #get_name_interned_predeclaration = \
4631 #"static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/"
4633 #------------------------------------------------------------------------------------
4635 printing_utility_code = UtilityCode(
4636 proto = """
4637 static int __Pyx_Print(PyObject *, int); /*proto*/
4638 #if PY_MAJOR_VERSION >= 3
4639 static PyObject* %s = 0;
4640 static PyObject* %s = 0;
4641 #endif
4642 """ % (Naming.print_function, Naming.print_function_kwargs),
4643 impl = r"""
4644 #if PY_MAJOR_VERSION < 3
4645 static PyObject *__Pyx_GetStdout(void) {
4646 PyObject *f = PySys_GetObject((char *)"stdout");
4647 if (!f) {
4648 PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout");
4650 return f;
4653 static int __Pyx_Print(PyObject *arg_tuple, int newline) {
4654 PyObject *f;
4655 PyObject* v;
4656 int i;
4658 if (!(f = __Pyx_GetStdout()))
4659 return -1;
4660 for (i=0; i < PyTuple_GET_SIZE(arg_tuple); i++) {
4661 if (PyFile_SoftSpace(f, 1)) {
4662 if (PyFile_WriteString(" ", f) < 0)
4663 return -1;
4665 v = PyTuple_GET_ITEM(arg_tuple, i);
4666 if (PyFile_WriteObject(v, f, Py_PRINT_RAW) < 0)
4667 return -1;
4668 if (PyString_Check(v)) {
4669 char *s = PyString_AsString(v);
4670 Py_ssize_t len = PyString_Size(v);
4671 if (len > 0 &&
4672 isspace(Py_CHARMASK(s[len-1])) &&
4673 s[len-1] != ' ')
4674 PyFile_SoftSpace(f, 0);
4677 if (newline) {
4678 if (PyFile_WriteString("\n", f) < 0)
4679 return -1;
4680 PyFile_SoftSpace(f, 0);
4682 return 0;
4685 #else /* Python 3 has a print function */
4686 static int __Pyx_Print(PyObject *arg_tuple, int newline) {
4687 PyObject* kwargs = 0;
4688 PyObject* result = 0;
4689 PyObject* end_string;
4690 if (!%(PRINT_FUNCTION)s) {
4691 %(PRINT_FUNCTION)s = PyObject_GetAttrString(%(BUILTINS)s, "print");
4692 if (!%(PRINT_FUNCTION)s)
4693 return -1;
4695 if (!newline) {
4696 if (!%(PRINT_KWARGS)s) {
4697 %(PRINT_KWARGS)s = PyDict_New();
4698 if (!%(PRINT_KWARGS)s)
4699 return -1;
4700 end_string = PyUnicode_FromStringAndSize(" ", 1);
4701 if (!end_string)
4702 return -1;
4703 if (PyDict_SetItemString(%(PRINT_KWARGS)s, "end", end_string) < 0) {
4704 Py_DECREF(end_string);
4705 return -1;
4707 Py_DECREF(end_string);
4709 kwargs = %(PRINT_KWARGS)s;
4711 result = PyObject_Call(%(PRINT_FUNCTION)s, arg_tuple, kwargs);
4712 if (!result)
4713 return -1;
4714 Py_DECREF(result);
4715 return 0;
4717 #endif
4718 """ % {'BUILTINS' : Naming.builtins_cname,
4719 'PRINT_FUNCTION' : Naming.print_function,
4720 'PRINT_KWARGS' : Naming.print_function_kwargs}
4723 #------------------------------------------------------------------------------------
4725 # The following function is based on do_raise() from ceval.c.
4727 raise_utility_code = UtilityCode(
4728 proto = """
4729 static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
4730 """,
4731 impl = """
4732 static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
4733 Py_XINCREF(type);
4734 Py_XINCREF(value);
4735 Py_XINCREF(tb);
4736 /* First, check the traceback argument, replacing None with NULL. */
4737 if (tb == Py_None) {
4738 Py_DECREF(tb);
4739 tb = 0;
4741 else if (tb != NULL && !PyTraceBack_Check(tb)) {
4742 PyErr_SetString(PyExc_TypeError,
4743 "raise: arg 3 must be a traceback or None");
4744 goto raise_error;
4746 /* Next, replace a missing value with None */
4747 if (value == NULL) {
4748 value = Py_None;
4749 Py_INCREF(value);
4751 #if PY_VERSION_HEX < 0x02050000
4752 if (!PyClass_Check(type))
4753 #else
4754 if (!PyType_Check(type))
4755 #endif
4757 /* Raising an instance. The value should be a dummy. */
4758 if (value != Py_None) {
4759 PyErr_SetString(PyExc_TypeError,
4760 "instance exception may not have a separate value");
4761 goto raise_error;
4763 /* Normalize to raise <class>, <instance> */
4764 Py_DECREF(value);
4765 value = type;
4766 #if PY_VERSION_HEX < 0x02050000
4767 if (PyInstance_Check(type)) {
4768 type = (PyObject*) ((PyInstanceObject*)type)->in_class;
4769 Py_INCREF(type);
4771 else {
4772 type = 0;
4773 PyErr_SetString(PyExc_TypeError,
4774 "raise: exception must be an old-style class or instance");
4775 goto raise_error;
4777 #else
4778 type = (PyObject*) Py_TYPE(type);
4779 Py_INCREF(type);
4780 if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) {
4781 PyErr_SetString(PyExc_TypeError,
4782 "raise: exception class must be a subclass of BaseException");
4783 goto raise_error;
4785 #endif
4787 __Pyx_ErrRestore(type, value, tb);
4788 return;
4789 raise_error:
4790 Py_XDECREF(value);
4791 Py_XDECREF(type);
4792 Py_XDECREF(tb);
4793 return;
4795 """)
4797 #------------------------------------------------------------------------------------
4799 reraise_utility_code = UtilityCode(
4800 proto = """
4801 static void __Pyx_ReRaise(void); /*proto*/
4802 """,
4803 impl = """
4804 static void __Pyx_ReRaise(void) {
4805 PyThreadState *tstate = PyThreadState_Get();
4806 PyObject *type = tstate->exc_type;
4807 PyObject *value = tstate->exc_value;
4808 PyObject *tb = tstate->exc_traceback;
4809 Py_XINCREF(type);
4810 Py_XINCREF(value);
4811 Py_XINCREF(tb);
4812 __Pyx_ErrRestore(type, value, tb);
4814 """)
4816 #------------------------------------------------------------------------------------
4818 arg_type_test_utility_code = UtilityCode(
4819 proto = """
4820 static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed,
4821 const char *name, int exact); /*proto*/
4822 """,
4823 impl = """
4824 static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed,
4825 const char *name, int exact)
4827 if (!type) {
4828 PyErr_Format(PyExc_SystemError, "Missing type object");
4829 return 0;
4831 if (none_allowed && obj == Py_None) return 1;
4832 else if (exact) {
4833 if (Py_TYPE(obj) == type) return 1;
4835 else {
4836 if (PyObject_TypeCheck(obj, type)) return 1;
4838 PyErr_Format(PyExc_TypeError,
4839 "Argument '%s' has incorrect type (expected %s, got %s)",
4840 name, type->tp_name, Py_TYPE(obj)->tp_name);
4841 return 0;
4843 """)
4845 #------------------------------------------------------------------------------------
4847 # __Pyx_RaiseArgtupleInvalid raises the correct exception when too
4848 # many or too few positional arguments were found. This handles
4849 # Py_ssize_t formatting correctly.
4851 raise_argtuple_invalid_utility_code = UtilityCode(
4852 proto = """
4853 static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
4854 Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); /*proto*/
4855 """,
4856 impl = """
4857 static void __Pyx_RaiseArgtupleInvalid(
4858 const char* func_name,
4859 int exact,
4860 Py_ssize_t num_min,
4861 Py_ssize_t num_max,
4862 Py_ssize_t num_found)
4864 Py_ssize_t num_expected;
4865 const char *number, *more_or_less;
4867 if (num_found < num_min) {
4868 num_expected = num_min;
4869 more_or_less = "at least";
4870 } else {
4871 num_expected = num_max;
4872 more_or_less = "at most";
4874 if (exact) {
4875 more_or_less = "exactly";
4877 number = (num_expected == 1) ? "" : "s";
4878 PyErr_Format(PyExc_TypeError,
4879 #if PY_VERSION_HEX < 0x02050000
4880 "%s() takes %s %d positional argument%s (%d given)",
4881 #else
4882 "%s() takes %s %zd positional argument%s (%zd given)",
4883 #endif
4884 func_name, more_or_less, num_expected, number, num_found);
4886 """)
4888 raise_keyword_required_utility_code = UtilityCode(
4889 proto = """
4890 static INLINE void __Pyx_RaiseKeywordRequired(const char* func_name, PyObject* kw_name); /*proto*/
4891 """,
4892 impl = """
4893 static INLINE void __Pyx_RaiseKeywordRequired(
4894 const char* func_name,
4895 PyObject* kw_name)
4897 PyErr_Format(PyExc_TypeError,
4898 #if PY_MAJOR_VERSION >= 3
4899 "%s() needs keyword-only argument %U", func_name, kw_name);
4900 #else
4901 "%s() needs keyword-only argument %s", func_name,
4902 PyString_AS_STRING(kw_name));
4903 #endif
4905 """)
4907 raise_double_keywords_utility_code = UtilityCode(
4908 proto = """
4909 static void __Pyx_RaiseDoubleKeywordsError(
4910 const char* func_name, PyObject* kw_name); /*proto*/
4911 """,
4912 impl = """
4913 static void __Pyx_RaiseDoubleKeywordsError(
4914 const char* func_name,
4915 PyObject* kw_name)
4917 PyErr_Format(PyExc_TypeError,
4918 #if PY_MAJOR_VERSION >= 3
4919 "%s() got multiple values for keyword argument '%U'", func_name, kw_name);
4920 #else
4921 "%s() got multiple values for keyword argument '%s'", func_name,
4922 PyString_AS_STRING(kw_name));
4923 #endif
4925 """)
4927 #------------------------------------------------------------------------------------
4929 # __Pyx_CheckKeywordStrings raises an error if non-string keywords
4930 # were passed to a function, or if any keywords were passed to a
4931 # function that does not accept them.
4933 keyword_string_check_utility_code = UtilityCode(
4934 proto = """
4935 static INLINE int __Pyx_CheckKeywordStrings(PyObject *kwdict,
4936 const char* function_name, int kw_allowed); /*proto*/
4937 """,
4938 impl = """
4939 static INLINE int __Pyx_CheckKeywordStrings(
4940 PyObject *kwdict,
4941 const char* function_name,
4942 int kw_allowed)
4944 PyObject* key = 0;
4945 Py_ssize_t pos = 0;
4946 while (PyDict_Next(kwdict, &pos, &key, 0)) {
4947 #if PY_MAJOR_VERSION < 3
4948 if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key)))
4949 #else
4950 if (unlikely(!PyUnicode_CheckExact(key)) && unlikely(!PyUnicode_Check(key)))
4951 #endif
4952 goto invalid_keyword_type;
4954 if ((!kw_allowed) && unlikely(key))
4955 goto invalid_keyword;
4956 return 1;
4957 invalid_keyword_type:
4958 PyErr_Format(PyExc_TypeError,
4959 "%s() keywords must be strings", function_name);
4960 return 0;
4961 invalid_keyword:
4962 PyErr_Format(PyExc_TypeError,
4963 #if PY_MAJOR_VERSION < 3
4964 "%s() got an unexpected keyword argument '%s'",
4965 function_name, PyString_AsString(key));
4966 #else
4967 "%s() got an unexpected keyword argument '%U'",
4968 function_name, key);
4969 #endif
4970 return 0;
4972 """)
4974 #------------------------------------------------------------------------------------
4976 # __Pyx_ParseOptionalKeywords copies the optional/unknown keyword
4977 # arguments from the kwds dict into kwds2. If kwds2 is NULL, unknown
4978 # keywords will raise an invalid keyword error.
4980 # Three kinds of errors are checked: 1) non-string keywords, 2)
4981 # unexpected keywords and 3) overlap with positional arguments.
4983 # If num_posargs is greater 0, it denotes the number of positional
4984 # arguments that were passed and that must therefore not appear
4985 # amongst the keywords as well.
4987 # This method does not check for required keyword arguments.
4990 parse_keywords_utility_code = UtilityCode(
4991 proto = """
4992 static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[], \
4993 PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, \
4994 const char* function_name); /*proto*/
4995 """,
4996 impl = """
4997 static int __Pyx_ParseOptionalKeywords(
4998 PyObject *kwds,
4999 PyObject **argnames[],
5000 PyObject *kwds2,
5001 PyObject *values[],
5002 Py_ssize_t num_pos_args,
5003 const char* function_name)
5005 PyObject *key = 0, *value = 0;
5006 Py_ssize_t pos = 0;
5007 PyObject*** name;
5008 PyObject*** first_kw_arg = argnames + num_pos_args;
5010 while (PyDict_Next(kwds, &pos, &key, &value)) {
5011 #if PY_MAJOR_VERSION < 3
5012 if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key))) {
5013 #else
5014 if (unlikely(!PyUnicode_CheckExact(key)) && unlikely(!PyUnicode_Check(key))) {
5015 #endif
5016 goto invalid_keyword_type;
5017 } else {
5018 name = argnames;
5019 while (*name && (**name != key)) name++;
5020 if (*name) {
5021 if (name < first_kw_arg) goto arg_passed_twice;
5022 values[name-argnames] = value;
5023 } else {
5024 for (name = first_kw_arg; *name; name++) {
5025 #if PY_MAJOR_VERSION >= 3
5026 if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) &&
5027 PyUnicode_Compare(**name, key) == 0) break;
5028 #else
5029 if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) &&
5030 strcmp(PyString_AS_STRING(**name),
5031 PyString_AS_STRING(key)) == 0) break;
5032 #endif
5034 if (*name) {
5035 values[name-argnames] = value;
5036 } else {
5037 /* unexpected keyword found */
5038 for (name=argnames; name != first_kw_arg; name++) {
5039 if (**name == key) goto arg_passed_twice;
5040 #if PY_MAJOR_VERSION >= 3
5041 if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) &&
5042 PyUnicode_Compare(**name, key) == 0) goto arg_passed_twice;
5043 #else
5044 if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) &&
5045 strcmp(PyString_AS_STRING(**name),
5046 PyString_AS_STRING(key)) == 0) goto arg_passed_twice;
5047 #endif
5049 if (kwds2) {
5050 if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad;
5051 } else {
5052 goto invalid_keyword;
5058 return 0;
5059 arg_passed_twice:
5060 __Pyx_RaiseDoubleKeywordsError(function_name, **name);
5061 goto bad;
5062 invalid_keyword_type:
5063 PyErr_Format(PyExc_TypeError,
5064 "%s() keywords must be strings", function_name);
5065 goto bad;
5066 invalid_keyword:
5067 PyErr_Format(PyExc_TypeError,
5068 #if PY_MAJOR_VERSION < 3
5069 "%s() got an unexpected keyword argument '%s'",
5070 function_name, PyString_AsString(key));
5071 #else
5072 "%s() got an unexpected keyword argument '%U'",
5073 function_name, key);
5074 #endif
5075 bad:
5076 return -1;
5078 """)
5080 #------------------------------------------------------------------------------------
5082 unraisable_exception_utility_code = UtilityCode(
5083 proto = """
5084 static void __Pyx_WriteUnraisable(const char *name); /*proto*/
5085 """,
5086 impl = """
5087 static void __Pyx_WriteUnraisable(const char *name) {
5088 PyObject *old_exc, *old_val, *old_tb;
5089 PyObject *ctx;
5090 __Pyx_ErrFetch(&old_exc, &old_val, &old_tb);
5091 #if PY_MAJOR_VERSION < 3
5092 ctx = PyString_FromString(name);
5093 #else
5094 ctx = PyUnicode_FromString(name);
5095 #endif
5096 __Pyx_ErrRestore(old_exc, old_val, old_tb);
5097 if (!ctx) {
5098 PyErr_WriteUnraisable(Py_None);
5099 } else {
5100 PyErr_WriteUnraisable(ctx);
5101 Py_DECREF(ctx);
5104 """)
5106 #------------------------------------------------------------------------------------
5108 traceback_utility_code = UtilityCode(
5109 proto = """
5110 static void __Pyx_AddTraceback(const char *funcname); /*proto*/
5111 """,
5112 impl = """
5113 #include "compile.h"
5114 #include "frameobject.h"
5115 #include "traceback.h"
5117 static void __Pyx_AddTraceback(const char *funcname) {
5118 PyObject *py_srcfile = 0;
5119 PyObject *py_funcname = 0;
5120 PyObject *py_globals = 0;
5121 PyObject *empty_string = 0;
5122 PyCodeObject *py_code = 0;
5123 PyFrameObject *py_frame = 0;
5125 #if PY_MAJOR_VERSION < 3
5126 py_srcfile = PyString_FromString(%(FILENAME)s);
5127 #else
5128 py_srcfile = PyUnicode_FromString(%(FILENAME)s);
5129 #endif
5130 if (!py_srcfile) goto bad;
5131 if (%(CLINENO)s) {
5132 #if PY_MAJOR_VERSION < 3
5133 py_funcname = PyString_FromFormat( "%%s (%%s:%%d)", funcname, %(CFILENAME)s, %(CLINENO)s);
5134 #else
5135 py_funcname = PyUnicode_FromFormat( "%%s (%%s:%%d)", funcname, %(CFILENAME)s, %(CLINENO)s);
5136 #endif
5138 else {
5139 #if PY_MAJOR_VERSION < 3
5140 py_funcname = PyString_FromString(funcname);
5141 #else
5142 py_funcname = PyUnicode_FromString(funcname);
5143 #endif
5145 if (!py_funcname) goto bad;
5146 py_globals = PyModule_GetDict(%(GLOBALS)s);
5147 if (!py_globals) goto bad;
5148 #if PY_MAJOR_VERSION < 3
5149 empty_string = PyString_FromStringAndSize("", 0);
5150 #else
5151 empty_string = PyBytes_FromStringAndSize("", 0);
5152 #endif
5153 if (!empty_string) goto bad;
5154 py_code = PyCode_New(
5155 0, /*int argcount,*/
5156 #if PY_MAJOR_VERSION >= 3
5157 0, /*int kwonlyargcount,*/
5158 #endif
5159 0, /*int nlocals,*/
5160 0, /*int stacksize,*/
5161 0, /*int flags,*/
5162 empty_string, /*PyObject *code,*/
5163 %(EMPTY_TUPLE)s, /*PyObject *consts,*/
5164 %(EMPTY_TUPLE)s, /*PyObject *names,*/
5165 %(EMPTY_TUPLE)s, /*PyObject *varnames,*/
5166 %(EMPTY_TUPLE)s, /*PyObject *freevars,*/
5167 %(EMPTY_TUPLE)s, /*PyObject *cellvars,*/
5168 py_srcfile, /*PyObject *filename,*/
5169 py_funcname, /*PyObject *name,*/
5170 %(LINENO)s, /*int firstlineno,*/
5171 empty_string /*PyObject *lnotab*/
5172 );
5173 if (!py_code) goto bad;
5174 py_frame = PyFrame_New(
5175 PyThreadState_GET(), /*PyThreadState *tstate,*/
5176 py_code, /*PyCodeObject *code,*/
5177 py_globals, /*PyObject *globals,*/
5178 0 /*PyObject *locals*/
5179 );
5180 if (!py_frame) goto bad;
5181 py_frame->f_lineno = %(LINENO)s;
5182 PyTraceBack_Here(py_frame);
5183 bad:
5184 Py_XDECREF(py_srcfile);
5185 Py_XDECREF(py_funcname);
5186 Py_XDECREF(empty_string);
5187 Py_XDECREF(py_code);
5188 Py_XDECREF(py_frame);
5190 """ % {
5191 'FILENAME': Naming.filename_cname,
5192 'LINENO': Naming.lineno_cname,
5193 'CFILENAME': Naming.cfilenm_cname,
5194 'CLINENO': Naming.clineno_cname,
5195 'GLOBALS': Naming.module_cname,
5196 'EMPTY_TUPLE' : Naming.empty_tuple,
5197 })
5199 restore_exception_utility_code = UtilityCode(
5200 proto = """
5201 static INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
5202 static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
5203 """,
5204 impl = """
5205 static INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) {
5206 PyObject *tmp_type, *tmp_value, *tmp_tb;
5207 PyThreadState *tstate = PyThreadState_GET();
5209 tmp_type = tstate->curexc_type;
5210 tmp_value = tstate->curexc_value;
5211 tmp_tb = tstate->curexc_traceback;
5212 tstate->curexc_type = type;
5213 tstate->curexc_value = value;
5214 tstate->curexc_traceback = tb;
5215 Py_XDECREF(tmp_type);
5216 Py_XDECREF(tmp_value);
5217 Py_XDECREF(tmp_tb);
5220 static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) {
5221 PyThreadState *tstate = PyThreadState_GET();
5222 *type = tstate->curexc_type;
5223 *value = tstate->curexc_value;
5224 *tb = tstate->curexc_traceback;
5226 tstate->curexc_type = 0;
5227 tstate->curexc_value = 0;
5228 tstate->curexc_traceback = 0;
5231 """)
5233 #------------------------------------------------------------------------------------
5235 set_vtable_utility_code = UtilityCode(
5236 proto = """
5237 static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
5238 """,
5239 impl = """
5240 static int __Pyx_SetVtable(PyObject *dict, void *vtable) {
5241 PyObject *pycobj = 0;
5242 int result;
5244 pycobj = PyCObject_FromVoidPtr(vtable, 0);
5245 if (!pycobj)
5246 goto bad;
5247 if (PyDict_SetItemString(dict, "__pyx_vtable__", pycobj) < 0)
5248 goto bad;
5249 result = 0;
5250 goto done;
5252 bad:
5253 result = -1;
5254 done:
5255 Py_XDECREF(pycobj);
5256 return result;
5258 """)
5260 #------------------------------------------------------------------------------------
5262 get_vtable_utility_code = UtilityCode(
5263 proto = """
5264 static int __Pyx_GetVtable(PyObject *dict, void *vtabptr); /*proto*/
5265 """,
5266 impl = r"""
5267 static int __Pyx_GetVtable(PyObject *dict, void *vtabptr) {
5268 int result;
5269 PyObject *pycobj;
5271 pycobj = PyMapping_GetItemString(dict, (char *)"__pyx_vtable__");
5272 if (!pycobj)
5273 goto bad;
5274 *(void **)vtabptr = PyCObject_AsVoidPtr(pycobj);
5275 if (!*(void **)vtabptr)
5276 goto bad;
5277 result = 0;
5278 goto done;
5280 bad:
5281 result = -1;
5282 done:
5283 Py_XDECREF(pycobj);
5284 return result;
5286 """)
5288 #------------------------------------------------------------------------------------
5290 init_string_tab_utility_code = UtilityCode(
5291 proto = """
5292 static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/
5293 """,
5294 impl = """
5295 static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
5296 while (t->p) {
5297 #if PY_MAJOR_VERSION < 3
5298 if (t->is_unicode && (!t->is_identifier)) {
5299 *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL);
5300 } else if (t->intern) {
5301 *t->p = PyString_InternFromString(t->s);
5302 } else {
5303 *t->p = PyString_FromStringAndSize(t->s, t->n - 1);
5305 #else /* Python 3+ has unicode identifiers */
5306 if (t->is_identifier || (t->is_unicode && t->intern)) {
5307 *t->p = PyUnicode_InternFromString(t->s);
5308 } else if (t->is_unicode) {
5309 *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1);
5310 } else {
5311 *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1);
5313 #endif
5314 if (!*t->p)
5315 return -1;
5316 ++t;
5318 return 0;
5320 """)
5322 #------------------------------------------------------------------------------------
5324 get_exception_utility_code = UtilityCode(
5325 proto = """
5326 static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
5327 """,
5328 impl = """
5329 static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) {
5330 PyObject *tmp_type, *tmp_value, *tmp_tb;
5331 PyThreadState *tstate = PyThreadState_GET();
5332 __Pyx_ErrFetch(type, value, tb);
5333 PyErr_NormalizeException(type, value, tb);
5334 if (PyErr_Occurred())
5335 goto bad;
5336 Py_INCREF(*type);
5337 Py_INCREF(*value);
5338 Py_INCREF(*tb);
5339 tmp_type = tstate->exc_type;
5340 tmp_value = tstate->exc_value;
5341 tmp_tb = tstate->exc_traceback;
5342 tstate->exc_type = *type;
5343 tstate->exc_value = *value;
5344 tstate->exc_traceback = *tb;
5345 /* Make sure tstate is in a consistent state when we XDECREF
5346 these objects (XDECREF may run arbitrary code). */
5347 Py_XDECREF(tmp_type);
5348 Py_XDECREF(tmp_value);
5349 Py_XDECREF(tmp_tb);
5350 return 0;
5351 bad:
5352 Py_XDECREF(*type);
5353 Py_XDECREF(*value);
5354 Py_XDECREF(*tb);
5355 return -1;
5358 """)
5360 #------------------------------------------------------------------------------------
5362 reset_exception_utility_code = UtilityCode(
5363 proto = """
5364 static INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
5365 static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
5366 """,
5367 impl = """
5368 static INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb) {
5369 PyThreadState *tstate = PyThreadState_GET();
5370 *type = tstate->exc_type;
5371 *value = tstate->exc_value;
5372 *tb = tstate->exc_traceback;
5373 Py_XINCREF(*type);
5374 Py_XINCREF(*value);
5375 Py_XINCREF(*tb);
5378 static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb) {
5379 PyObject *tmp_type, *tmp_value, *tmp_tb;
5380 PyThreadState *tstate = PyThreadState_GET();
5381 tmp_type = tstate->exc_type;
5382 tmp_value = tstate->exc_value;
5383 tmp_tb = tstate->exc_traceback;
5384 tstate->exc_type = type;
5385 tstate->exc_value = value;
5386 tstate->exc_traceback = tb;
5387 Py_XDECREF(tmp_type);
5388 Py_XDECREF(tmp_value);
5389 Py_XDECREF(tmp_tb);
5391 """)
5393 #------------------------------------------------------------------------------------