1# 2# Parse tree nodes 3# 4 5from __future__ import absolute_import 6 7import cython 8cython.declare(sys=object, os=object, copy=object, 9 Builtin=object, error=object, warning=object, Naming=object, PyrexTypes=object, 10 py_object_type=object, ModuleScope=object, LocalScope=object, ClosureScope=object, 11 StructOrUnionScope=object, PyClassScope=object, 12 CppClassScope=object, UtilityCode=object, EncodedString=object, 13 error_type=object, _py_int_types=object) 14 15import sys, os, copy 16from itertools import chain 17 18from . import Builtin 19from .Errors import error, warning, InternalError, CompileError 20from . import Naming 21from . import PyrexTypes 22from . import TypeSlots 23from .PyrexTypes import py_object_type, error_type 24from .Symtab import (ModuleScope, LocalScope, ClosureScope, 25 StructOrUnionScope, PyClassScope, CppClassScope, TemplateScope) 26from .Code import UtilityCode 27from .StringEncoding import EncodedString 28from . import Future 29from . import Options 30from . import DebugFlags 31from .Pythran import has_np_pythran, pythran_type, is_pythran_buffer 32from ..Utils import add_metaclass 33 34 35if sys.version_info[0] >= 3: 36 _py_int_types = int 37else: 38 _py_int_types = (int, long) 39 40 41def relative_position(pos): 42 return (pos[0].get_filenametable_entry(), pos[1]) 43 44 45def embed_position(pos, docstring): 46 if not Options.embed_pos_in_docstring: 47 return docstring 48 pos_line = u'File: %s (starting at line %s)' % relative_position(pos) 49 if docstring is None: 50 # unicode string 51 return EncodedString(pos_line) 52 53 # make sure we can encode the filename in the docstring encoding 54 # otherwise make the docstring a unicode string 55 encoding = docstring.encoding 56 if encoding is not None: 57 try: 58 pos_line.encode(encoding) 59 except UnicodeEncodeError: 60 encoding = None 61 62 if not docstring: 63 # reuse the string encoding of the original docstring 64 doc = EncodedString(pos_line) 65 else: 66 doc = EncodedString(pos_line + u'\n' + docstring) 67 doc.encoding = encoding 68 return doc 69 70 71def analyse_type_annotation(annotation, env, assigned_value=None): 72 base_type = None 73 is_ambiguous = False 74 explicit_pytype = explicit_ctype = False 75 if annotation.is_dict_literal: 76 warning(annotation.pos, 77 "Dicts should no longer be used as type annotations. Use 'cython.int' etc. directly.") 78 for name, value in annotation.key_value_pairs: 79 if not name.is_string_literal: 80 continue 81 if name.value in ('type', b'type'): 82 explicit_pytype = True 83 if not explicit_ctype: 84 annotation = value 85 elif name.value in ('ctype', b'ctype'): 86 explicit_ctype = True 87 annotation = value 88 if explicit_pytype and explicit_ctype: 89 warning(annotation.pos, "Duplicate type declarations found in signature annotation") 90 arg_type = annotation.analyse_as_type(env) 91 if annotation.is_name and not annotation.cython_attribute and annotation.name in ('int', 'long', 'float'): 92 # Map builtin numeric Python types to C types in safe cases. 93 if assigned_value is not None and arg_type is not None and not arg_type.is_pyobject: 94 assigned_type = assigned_value.infer_type(env) 95 if assigned_type and assigned_type.is_pyobject: 96 # C type seems unsafe, e.g. due to 'None' default value => ignore annotation type 97 is_ambiguous = True 98 arg_type = None 99 # ignore 'int' and require 'cython.int' to avoid unsafe integer declarations 100 if arg_type in (PyrexTypes.c_long_type, PyrexTypes.c_int_type, PyrexTypes.c_float_type): 101 arg_type = PyrexTypes.c_double_type if annotation.name == 'float' else py_object_type 102 elif arg_type is not None and annotation.is_string_literal: 103 warning(annotation.pos, 104 "Strings should no longer be used for type declarations. Use 'cython.int' etc. directly.") 105 if arg_type is not None: 106 if explicit_pytype and not explicit_ctype and not arg_type.is_pyobject: 107 warning(annotation.pos, 108 "Python type declaration in signature annotation does not refer to a Python type") 109 base_type = CAnalysedBaseTypeNode( 110 annotation.pos, type=arg_type, is_arg=True) 111 elif is_ambiguous: 112 warning(annotation.pos, "Ambiguous types in annotation, ignoring") 113 else: 114 warning(annotation.pos, "Unknown type declaration in annotation, ignoring") 115 return base_type, arg_type 116 117 118def write_func_call(func, codewriter_class): 119 def f(*args, **kwds): 120 if len(args) > 1 and isinstance(args[1], codewriter_class): 121 # here we annotate the code with this function call 122 # but only if new code is generated 123 node, code = args[:2] 124 marker = ' /* %s -> %s.%s %s */' % ( 125 ' ' * code.call_level, 126 node.__class__.__name__, 127 func.__name__, 128 node.pos[1:]) 129 pristine = code.buffer.stream.tell() 130 code.putln(marker) 131 start = code.buffer.stream.tell() 132 code.call_level += 4 133 res = func(*args, **kwds) 134 code.call_level -= 4 135 if start == code.buffer.stream.tell(): 136 # no code written => undo writing marker 137 code.buffer.stream.truncate(pristine) 138 else: 139 marker = marker.replace('->', '<-', 1) 140 code.putln(marker) 141 return res 142 else: 143 return func(*args, **kwds) 144 return f 145 146 147class VerboseCodeWriter(type): 148 # Set this as a metaclass to trace function calls in code. 149 # This slows down code generation and makes much larger files. 150 def __new__(cls, name, bases, attrs): 151 from types import FunctionType 152 from .Code import CCodeWriter 153 attrs = dict(attrs) 154 for mname, m in attrs.items(): 155 if isinstance(m, FunctionType): 156 attrs[mname] = write_func_call(m, CCodeWriter) 157 return super(VerboseCodeWriter, cls).__new__(cls, name, bases, attrs) 158 159 160class CheckAnalysers(type): 161 """Metaclass to check that type analysis functions return a node. 162 """ 163 methods = set(['analyse_types', 164 'analyse_expressions', 165 'analyse_target_types']) 166 167 def __new__(cls, name, bases, attrs): 168 from types import FunctionType 169 def check(name, func): 170 def call(*args, **kwargs): 171 retval = func(*args, **kwargs) 172 if retval is None: 173 print('%s %s %s' % (name, args, kwargs)) 174 return retval 175 return call 176 177 attrs = dict(attrs) 178 for mname, m in attrs.items(): 179 if isinstance(m, FunctionType) and mname in cls.methods: 180 attrs[mname] = check(mname, m) 181 return super(CheckAnalysers, cls).__new__(cls, name, bases, attrs) 182 183 184def _with_metaclass(cls): 185 if DebugFlags.debug_trace_code_generation: 186 return add_metaclass(VerboseCodeWriter)(cls) 187 #return add_metaclass(CheckAnalysers)(cls) 188 return cls 189 190 191@_with_metaclass 192class Node(object): 193 # pos (string, int, int) Source file position 194 # is_name boolean Is a NameNode 195 # is_literal boolean Is a ConstNode 196 197 is_name = 0 198 is_none = 0 199 is_nonecheck = 0 200 is_literal = 0 201 is_terminator = 0 202 is_wrapper = False # is a DefNode wrapper for a C function 203 temps = None 204 205 # All descendants should set child_attrs to a list of the attributes 206 # containing nodes considered "children" in the tree. Each such attribute 207 # can either contain a single node or a list of nodes. See Visitor.py. 208 child_attrs = None 209 210 # Subset of attributes that are evaluated in the outer scope (e.g. function default arguments). 211 outer_attrs = None 212 213 cf_state = None 214 215 # This may be an additional (or 'actual') type that will be checked when 216 # this node is coerced to another type. This could be useful to set when 217 # the actual type to which it can coerce is known, but you want to leave 218 # the type a py_object_type 219 coercion_type = None 220 221 def __init__(self, pos, **kw): 222 self.pos = pos 223 self.__dict__.update(kw) 224 225 gil_message = "Operation" 226 227 nogil_check = None 228 in_nogil_context = False # For use only during code generation. 229 230 def gil_error(self, env=None): 231 error(self.pos, "%s not allowed without gil" % self.gil_message) 232 233 cpp_message = "Operation" 234 235 def cpp_check(self, env): 236 if not env.is_cpp(): 237 self.cpp_error() 238 239 def cpp_error(self): 240 error(self.pos, "%s only allowed in c++" % self.cpp_message) 241 242 def clone_node(self): 243 """Clone the node. This is defined as a shallow copy, except for member lists 244 amongst the child attributes (from get_child_accessors) which are also 245 copied. Lists containing child nodes are thus seen as a way for the node 246 to hold multiple children directly; the list is not treated as a separate 247 level in the tree.""" 248 result = copy.copy(self) 249 for attrname in result.child_attrs: 250 value = getattr(result, attrname) 251 if isinstance(value, list): 252 setattr(result, attrname, [x for x in value]) 253 return result 254 255 256 # 257 # There are 3 phases of parse tree processing, applied in order to 258 # all the statements in a given scope-block: 259 # 260 # (0) analyse_declarations 261 # Make symbol table entries for all declarations at the current 262 # level, both explicit (def, cdef, etc.) and implicit (assignment 263 # to an otherwise undeclared name). 264 # 265 # (1) analyse_expressions 266 # Determine the result types of expressions and fill in the 267 # 'type' attribute of each ExprNode. Insert coercion nodes into the 268 # tree where needed to convert to and from Python objects. 269 # Allocate temporary locals for intermediate results. Fill 270 # in the 'result_code' attribute of each ExprNode with a C code 271 # fragment. 272 # 273 # (2) generate_code 274 # Emit C code for all declarations, statements and expressions. 275 # Recursively applies the 3 processing phases to the bodies of 276 # functions. 277 # 278 279 def analyse_declarations(self, env): 280 pass 281 282 def analyse_expressions(self, env): 283 raise InternalError("analyse_expressions not implemented for %s" % \ 284 self.__class__.__name__) 285 286 def generate_code(self, code): 287 raise InternalError("generate_code not implemented for %s" % \ 288 self.__class__.__name__) 289 290 def annotate(self, code): 291 # mro does the wrong thing 292 if isinstance(self, BlockNode): 293 self.body.annotate(code) 294 295 def end_pos(self): 296 try: 297 return self._end_pos 298 except AttributeError: 299 pos = self.pos 300 if not self.child_attrs: 301 self._end_pos = pos 302 return pos 303 for attr in self.child_attrs: 304 child = getattr(self, attr) 305 # Sometimes lists, sometimes nodes 306 if child is None: 307 pass 308 elif isinstance(child, list): 309 for c in child: 310 pos = max(pos, c.end_pos()) 311 else: 312 pos = max(pos, child.end_pos()) 313 self._end_pos = pos 314 return pos 315 316 def dump(self, level=0, filter_out=("pos",), cutoff=100, encountered=None): 317 """Debug helper method that returns a recursive string representation of this node. 318 """ 319 if cutoff == 0: 320 return "<...nesting level cutoff...>" 321 if encountered is None: 322 encountered = set() 323 if id(self) in encountered: 324 return "<%s (0x%x) -- already output>" % (self.__class__.__name__, id(self)) 325 encountered.add(id(self)) 326 327 def dump_child(x, level): 328 if isinstance(x, Node): 329 return x.dump(level, filter_out, cutoff-1, encountered) 330 elif isinstance(x, list): 331 return "[%s]" % ", ".join([dump_child(item, level) for item in x]) 332 else: 333 return repr(x) 334 335 attrs = [(key, value) for key, value in self.__dict__.items() if key not in filter_out] 336 if len(attrs) == 0: 337 return "<%s (0x%x)>" % (self.__class__.__name__, id(self)) 338 else: 339 indent = " " * level 340 res = "<%s (0x%x)\n" % (self.__class__.__name__, id(self)) 341 for key, value in attrs: 342 res += "%s %s: %s\n" % (indent, key, dump_child(value, level + 1)) 343 res += "%s>" % indent 344 return res 345 346 def dump_pos(self, mark_column=False, marker='(#)'): 347 """Debug helper method that returns the source code context of this node as a string. 348 """ 349 if not self.pos: 350 return u'' 351 source_desc, line, col = self.pos 352 contents = source_desc.get_lines(encoding='ASCII', error_handling='ignore') 353 # line numbers start at 1 354 lines = contents[max(0, line-3):line] 355 current = lines[-1] 356 if mark_column: 357 current = current[:col] + marker + current[col:] 358 lines[-1] = current.rstrip() + u' # <<<<<<<<<<<<<<\n' 359 lines += contents[line:line+2] 360 return u'"%s":%d:%d\n%s\n' % ( 361 source_desc.get_escaped_description(), line, col, u''.join(lines)) 362 363class CompilerDirectivesNode(Node): 364 """ 365 Sets compiler directives for the children nodes 366 """ 367 # directives {string:value} A dictionary holding the right value for 368 # *all* possible directives. 369 # body Node 370 child_attrs = ["body"] 371 372 def analyse_declarations(self, env): 373 old = env.directives 374 env.directives = self.directives 375 self.body.analyse_declarations(env) 376 env.directives = old 377 378 def analyse_expressions(self, env): 379 old = env.directives 380 env.directives = self.directives 381 self.body = self.body.analyse_expressions(env) 382 env.directives = old 383 return self 384 385 def generate_function_definitions(self, env, code): 386 env_old = env.directives 387 code_old = code.globalstate.directives 388 code.globalstate.directives = self.directives 389 self.body.generate_function_definitions(env, code) 390 env.directives = env_old 391 code.globalstate.directives = code_old 392 393 def generate_execution_code(self, code): 394 old = code.globalstate.directives 395 code.globalstate.directives = self.directives 396 self.body.generate_execution_code(code) 397 code.globalstate.directives = old 398 399 def annotate(self, code): 400 old = code.globalstate.directives 401 code.globalstate.directives = self.directives 402 self.body.annotate(code) 403 code.globalstate.directives = old 404 405class BlockNode(object): 406 # Mixin class for nodes representing a declaration block. 407 408 def generate_cached_builtins_decls(self, env, code): 409 entries = env.global_scope().undeclared_cached_builtins 410 for entry in entries: 411 code.globalstate.add_cached_builtin_decl(entry) 412 del entries[:] 413 414 def generate_lambda_definitions(self, env, code): 415 for node in env.lambda_defs: 416 node.generate_function_definitions(env, code) 417 418class StatListNode(Node): 419 # stats a list of StatNode 420 421 child_attrs = ["stats"] 422 423 @staticmethod 424 def create_analysed(pos, env, *args, **kw): 425 node = StatListNode(pos, *args, **kw) 426 return node # No node-specific analysis needed 427 428 def analyse_declarations(self, env): 429 #print "StatListNode.analyse_declarations" ### 430 for stat in self.stats: 431 stat.analyse_declarations(env) 432 433 def analyse_expressions(self, env): 434 #print "StatListNode.analyse_expressions" ### 435 self.stats = [stat.analyse_expressions(env) 436 for stat in self.stats] 437 return self 438 439 def generate_function_definitions(self, env, code): 440 #print "StatListNode.generate_function_definitions" ### 441 for stat in self.stats: 442 stat.generate_function_definitions(env, code) 443 444 def generate_execution_code(self, code): 445 #print "StatListNode.generate_execution_code" ### 446 for stat in self.stats: 447 code.mark_pos(stat.pos) 448 stat.generate_execution_code(code) 449 450 def annotate(self, code): 451 for stat in self.stats: 452 stat.annotate(code) 453 454 455class StatNode(Node): 456 # 457 # Code generation for statements is split into the following subphases: 458 # 459 # (1) generate_function_definitions 460 # Emit C code for the definitions of any structs, 461 # unions, enums and functions defined in the current 462 # scope-block. 463 # 464 # (2) generate_execution_code 465 # Emit C code for executable statements. 466 # 467 468 def generate_function_definitions(self, env, code): 469 pass 470 471 def generate_execution_code(self, code): 472 raise InternalError("generate_execution_code not implemented for %s" % \ 473 self.__class__.__name__) 474 475 476class CDefExternNode(StatNode): 477 # include_file string or None 478 # verbatim_include string or None 479 # body StatListNode 480 481 child_attrs = ["body"] 482 483 def analyse_declarations(self, env): 484 old_cinclude_flag = env.in_cinclude 485 env.in_cinclude = 1 486 self.body.analyse_declarations(env) 487 env.in_cinclude = old_cinclude_flag 488 489 if self.include_file or self.verbatim_include: 490 # Determine whether include should be late 491 stats = self.body.stats 492 if not env.directives['preliminary_late_includes_cy28']: 493 late = False 494 elif not stats: 495 # Special case: empty 'cdef extern' blocks are early 496 late = False 497 else: 498 late = all(isinstance(node, CVarDefNode) for node in stats) 499 env.add_include_file(self.include_file, self.verbatim_include, late) 500 501 def analyse_expressions(self, env): 502 return self 503 504 def generate_execution_code(self, code): 505 pass 506 507 def annotate(self, code): 508 self.body.annotate(code) 509 510 511class CDeclaratorNode(Node): 512 # Part of a C declaration. 513 # 514 # Processing during analyse_declarations phase: 515 # 516 # analyse 517 # Returns (name, type) pair where name is the 518 # CNameDeclaratorNode of the name being declared 519 # and type is the type it is being declared as. 520 # 521 # calling_convention string Calling convention of CFuncDeclaratorNode 522 # for which this is a base 523 524 child_attrs = [] 525 526 calling_convention = "" 527 528 def analyse_templates(self): 529 # Only C++ functions have templates. 530 return None 531 532 533class CNameDeclaratorNode(CDeclaratorNode): 534 # name string The Cython name being declared 535 # cname string or None C name, if specified 536 # default ExprNode or None the value assigned on declaration 537 538 child_attrs = ['default'] 539 540 default = None 541 542 def analyse(self, base_type, env, nonempty=0, visibility=None, in_pxd=False): 543 if nonempty and self.name == '': 544 # May have mistaken the name for the type. 545 if base_type.is_ptr or base_type.is_array or base_type.is_buffer: 546 error(self.pos, "Missing argument name") 547 elif base_type.is_void: 548 error(self.pos, "Use spam() rather than spam(void) to declare a function with no arguments.") 549 else: 550 self.name = base_type.declaration_code("", for_display=1, pyrex=1) 551 base_type = py_object_type 552 553 if base_type.is_fused and env.fused_to_specific: 554 base_type = base_type.specialize(env.fused_to_specific) 555 556 self.type = base_type 557 return self, base_type 558 559 560class CPtrDeclaratorNode(CDeclaratorNode): 561 # base CDeclaratorNode 562 563 child_attrs = ["base"] 564 565 def analyse_templates(self): 566 return self.base.analyse_templates() 567 568 def analyse(self, base_type, env, nonempty=0, visibility=None, in_pxd=False): 569 if base_type.is_pyobject: 570 error(self.pos, "Pointer base type cannot be a Python object") 571 ptr_type = PyrexTypes.c_ptr_type(base_type) 572 return self.base.analyse(ptr_type, env, nonempty=nonempty, visibility=visibility, in_pxd=in_pxd) 573 574 575class CReferenceDeclaratorNode(CDeclaratorNode): 576 # base CDeclaratorNode 577 578 child_attrs = ["base"] 579 580 def analyse_templates(self): 581 return self.base.analyse_templates() 582 583 def analyse(self, base_type, env, nonempty=0, visibility=None, in_pxd=False): 584 if base_type.is_pyobject: 585 error(self.pos, "Reference base type cannot be a Python object") 586 ref_type = PyrexTypes.c_ref_type(base_type) 587 return self.base.analyse(ref_type, env, nonempty=nonempty, visibility=visibility, in_pxd=in_pxd) 588 589 590class CArrayDeclaratorNode(CDeclaratorNode): 591 # base CDeclaratorNode 592 # dimension ExprNode 593 594 child_attrs = ["base", "dimension"] 595 596 def analyse(self, base_type, env, nonempty=0, visibility=None, in_pxd=False): 597 if (base_type.is_cpp_class and base_type.is_template_type()) or base_type.is_cfunction: 598 from .ExprNodes import TupleNode 599 if isinstance(self.dimension, TupleNode): 600 args = self.dimension.args 601 else: 602 args = self.dimension, 603 values = [v.analyse_as_type(env) for v in args] 604 if None in values: 605 ix = values.index(None) 606 error(args[ix].pos, "Template parameter not a type") 607 base_type = error_type 608 else: 609 base_type = base_type.specialize_here(self.pos, values) 610 return self.base.analyse(base_type, env, nonempty=nonempty, visibility=visibility, in_pxd=in_pxd) 611 if self.dimension: 612 self.dimension = self.dimension.analyse_const_expression(env) 613 if not self.dimension.type.is_int: 614 error(self.dimension.pos, "Array dimension not integer") 615 size = self.dimension.get_constant_c_result_code() 616 if size is not None: 617 try: 618 size = int(size) 619 except ValueError: 620 # runtime constant? 621 pass 622 else: 623 size = None 624 if not base_type.is_complete(): 625 error(self.pos, "Array element type '%s' is incomplete" % base_type) 626 if base_type.is_pyobject: 627 error(self.pos, "Array element cannot be a Python object") 628 if base_type.is_cfunction: 629 error(self.pos, "Array element cannot be a function") 630 array_type = PyrexTypes.c_array_type(base_type, size) 631 return self.base.analyse(array_type, env, nonempty=nonempty, visibility=visibility, in_pxd=in_pxd) 632 633 634class CFuncDeclaratorNode(CDeclaratorNode): 635 # base CDeclaratorNode 636 # args [CArgDeclNode] 637 # templates [TemplatePlaceholderType] 638 # has_varargs boolean 639 # exception_value ConstNode 640 # exception_check boolean True if PyErr_Occurred check needed 641 # nogil boolean Can be called without gil 642 # with_gil boolean Acquire gil around function body 643 # is_const_method boolean Whether this is a const method 644 645 child_attrs = ["base", "args", "exception_value"] 646 647 overridable = 0 648 optional_arg_count = 0 649 is_const_method = 0 650 templates = None 651 652 def analyse_templates(self): 653 if isinstance(self.base, CArrayDeclaratorNode): 654 from .ExprNodes import TupleNode, NameNode 655 template_node = self.base.dimension 656 if isinstance(template_node, TupleNode): 657 template_nodes = template_node.args 658 elif isinstance(template_node, NameNode): 659 template_nodes = [template_node] 660 else: 661 error(template_node.pos, "Template arguments must be a list of names") 662 return None 663 self.templates = [] 664 for template in template_nodes: 665 if isinstance(template, NameNode): 666 self.templates.append(PyrexTypes.TemplatePlaceholderType(template.name)) 667 else: 668 error(template.pos, "Template arguments must be a list of names") 669 self.base = self.base.base 670 return self.templates 671 else: 672 return None 673 674 def analyse(self, return_type, env, nonempty=0, directive_locals=None, visibility=None, in_pxd=False): 675 if directive_locals is None: 676 directive_locals = {} 677 if nonempty: 678 nonempty -= 1 679 func_type_args = [] 680 for i, arg_node in enumerate(self.args): 681 name_declarator, type = arg_node.analyse( 682 env, nonempty=nonempty, 683 is_self_arg=(i == 0 and env.is_c_class_scope and 'staticmethod' not in env.directives)) 684 name = name_declarator.name 685 if name in directive_locals: 686 type_node = directive_locals[name] 687 other_type = type_node.analyse_as_type(env) 688 if other_type is None: 689 error(type_node.pos, "Not a type") 690 elif (type is not PyrexTypes.py_object_type 691 and not type.same_as(other_type)): 692 error(self.base.pos, "Signature does not agree with previous declaration") 693 error(type_node.pos, "Previous declaration here") 694 else: 695 type = other_type 696 if name_declarator.cname: 697 error(self.pos, "Function argument cannot have C name specification") 698 if i == 0 and env.is_c_class_scope and type.is_unspecified: 699 # fix the type of self 700 type = env.parent_type 701 # Turn *[] argument into ** 702 if type.is_array: 703 type = PyrexTypes.c_ptr_type(type.base_type) 704 # Catch attempted C-style func(void) decl 705 if type.is_void: 706 error(arg_node.pos, "Use spam() rather than spam(void) to declare a function with no arguments.") 707 func_type_args.append( 708 PyrexTypes.CFuncTypeArg(name, type, arg_node.pos)) 709 if arg_node.default: 710 self.optional_arg_count += 1 711 elif self.optional_arg_count: 712 error(self.pos, "Non-default argument follows default argument") 713 714 exc_val = None 715 exc_check = 0 716 if self.exception_check == '+': 717 env.add_include_file('ios') # for std::ios_base::failure 718 env.add_include_file('new') # for std::bad_alloc 719 env.add_include_file('stdexcept') 720 env.add_include_file('typeinfo') # for std::bad_cast 721 if (return_type.is_pyobject 722 and (self.exception_value or self.exception_check) 723 and self.exception_check != '+'): 724 error(self.pos, "Exception clause not allowed for function returning Python object") 725 else: 726 if self.exception_value is None and self.exception_check and self.exception_check != '+': 727 # Use an explicit exception return value to speed up exception checks. 728 # Even if it is not declared, we can use the default exception value of the return type, 729 # unless the function is some kind of external function that we do not control. 730 if return_type.exception_value is not None and (visibility != 'extern' and not in_pxd): 731 # Extension types are more difficult because the signature must match the base type signature. 732 if not env.is_c_class_scope: 733 from .ExprNodes import ConstNode 734 self.exception_value = ConstNode( 735 self.pos, value=return_type.exception_value, type=return_type) 736 if self.exception_value: 737 self.exception_value = self.exception_value.analyse_const_expression(env) 738 if self.exception_check == '+': 739 exc_val_type = self.exception_value.type 740 if (not exc_val_type.is_error 741 and not exc_val_type.is_pyobject 742 and not (exc_val_type.is_cfunction 743 and not exc_val_type.return_type.is_pyobject 744 and not exc_val_type.args) 745 and not (exc_val_type == PyrexTypes.c_char_type 746 and self.exception_value.value == '*')): 747 error(self.exception_value.pos, 748 "Exception value must be a Python exception or cdef function with no arguments or *.") 749 exc_val = self.exception_value 750 else: 751 self.exception_value = self.exception_value.coerce_to( 752 return_type, env).analyse_const_expression(env) 753 exc_val = self.exception_value.get_constant_c_result_code() 754 if exc_val is None: 755 raise InternalError( 756 "get_constant_c_result_code not implemented for %s" % 757 self.exception_value.__class__.__name__) 758 if not return_type.assignable_from(self.exception_value.type): 759 error(self.exception_value.pos, 760 "Exception value incompatible with function return type") 761 exc_check = self.exception_check 762 if return_type.is_cfunction: 763 error(self.pos, "Function cannot return a function") 764 func_type = PyrexTypes.CFuncType( 765 return_type, func_type_args, self.has_varargs, 766 optional_arg_count=self.optional_arg_count, 767 exception_value=exc_val, exception_check=exc_check, 768 calling_convention=self.base.calling_convention, 769 nogil=self.nogil, with_gil=self.with_gil, is_overridable=self.overridable, 770 is_const_method=self.is_const_method, 771 templates=self.templates) 772 773 if self.optional_arg_count: 774 if func_type.is_fused: 775 # This is a bit of a hack... When we need to create specialized CFuncTypes 776 # on the fly because the cdef is defined in a pxd, we need to declare the specialized optional arg 777 # struct 778 def declare_opt_arg_struct(func_type, fused_cname): 779 self.declare_optional_arg_struct(func_type, env, fused_cname) 780 781 func_type.declare_opt_arg_struct = declare_opt_arg_struct 782 else: 783 self.declare_optional_arg_struct(func_type, env) 784 785 callspec = env.directives['callspec'] 786 if callspec: 787 current = func_type.calling_convention 788 if current and current != callspec: 789 error(self.pos, "cannot have both '%s' and '%s' " 790 "calling conventions" % (current, callspec)) 791 func_type.calling_convention = callspec 792 return self.base.analyse(func_type, env, visibility=visibility, in_pxd=in_pxd) 793 794 def declare_optional_arg_struct(self, func_type, env, fused_cname=None): 795 """ 796 Declares the optional argument struct (the struct used to hold the 797 values for optional arguments). For fused cdef functions, this is 798 deferred as analyse_declarations is called only once (on the fused 799 cdef function). 800 """ 801 scope = StructOrUnionScope() 802 arg_count_member = '%sn' % Naming.pyrex_prefix 803 scope.declare_var(arg_count_member, PyrexTypes.c_int_type, self.pos) 804 805 for arg in func_type.args[len(func_type.args) - self.optional_arg_count:]: 806 scope.declare_var(arg.name, arg.type, arg.pos, allow_pyobject=True, allow_memoryview=True) 807 808 struct_cname = env.mangle(Naming.opt_arg_prefix, self.base.name) 809 810 if fused_cname is not None: 811 struct_cname = PyrexTypes.get_fused_cname(fused_cname, struct_cname) 812 813 op_args_struct = env.global_scope().declare_struct_or_union( 814 name=struct_cname, 815 kind='struct', 816 scope=scope, 817 typedef_flag=0, 818 pos=self.pos, 819 cname=struct_cname) 820 821 op_args_struct.defined_in_pxd = 1 822 op_args_struct.used = 1 823 824 func_type.op_arg_struct = PyrexTypes.c_ptr_type(op_args_struct.type) 825 826 827class CConstDeclaratorNode(CDeclaratorNode): 828 # base CDeclaratorNode 829 830 child_attrs = ["base"] 831 832 def analyse(self, base_type, env, nonempty=0, visibility=None, in_pxd=False): 833 if base_type.is_pyobject: 834 error(self.pos, 835 "Const base type cannot be a Python object") 836 const = PyrexTypes.c_const_type(base_type) 837 return self.base.analyse(const, env, nonempty=nonempty, visibility=visibility, in_pxd=in_pxd) 838 839 840class CArgDeclNode(Node): 841 # Item in a function declaration argument list. 842 # 843 # base_type CBaseTypeNode 844 # declarator CDeclaratorNode 845 # not_none boolean Tagged with 'not None' 846 # or_none boolean Tagged with 'or None' 847 # accept_none boolean Resolved boolean for not_none/or_none 848 # default ExprNode or None 849 # default_value PyObjectConst constant for default value 850 # annotation ExprNode or None Py3 function arg annotation 851 # is_self_arg boolean Is the "self" arg of an extension type method 852 # is_type_arg boolean Is the "class" arg of an extension type classmethod 853 # is_kw_only boolean Is a keyword-only argument 854 # is_dynamic boolean Non-literal arg stored inside CyFunction 855 856 child_attrs = ["base_type", "declarator", "default", "annotation"] 857 outer_attrs = ["default", "annotation"] 858 859 is_self_arg = 0 860 is_type_arg = 0 861 is_generic = 1 862 kw_only = 0 863 not_none = 0 864 or_none = 0 865 type = None 866 name_declarator = None 867 default_value = None 868 annotation = None 869 is_dynamic = 0 870 871 def analyse(self, env, nonempty=0, is_self_arg=False): 872 if is_self_arg: 873 self.base_type.is_self_arg = self.is_self_arg = True 874 if self.type is None: 875 # The parser may misinterpret names as types. We fix that here. 876 if isinstance(self.declarator, CNameDeclaratorNode) and self.declarator.name == '': 877 if nonempty: 878 if self.base_type.is_basic_c_type: 879 # char, short, long called "int" 880 type = self.base_type.analyse(env, could_be_name=True) 881 arg_name = type.empty_declaration_code() 882 else: 883 arg_name = self.base_type.name 884 self.declarator.name = EncodedString(arg_name) 885 self.base_type.name = None 886 self.base_type.is_basic_c_type = False 887 could_be_name = True 888 else: 889 could_be_name = False 890 self.base_type.is_arg = True 891 base_type = self.base_type.analyse(env, could_be_name=could_be_name) 892 if hasattr(self.base_type, 'arg_name') and self.base_type.arg_name: 893 self.declarator.name = self.base_type.arg_name 894 895 # The parser is unable to resolve the ambiguity of [] as part of the 896 # type (e.g. in buffers) or empty declarator (as with arrays). 897 # This is only arises for empty multi-dimensional arrays. 898 if (base_type.is_array 899 and isinstance(self.base_type, TemplatedTypeNode) 900 and isinstance(self.declarator, CArrayDeclaratorNode)): 901 declarator = self.declarator 902 while isinstance(declarator.base, CArrayDeclaratorNode): 903 declarator = declarator.base 904 declarator.base = self.base_type.array_declarator 905 base_type = base_type.base_type 906 907 # inject type declaration from annotations 908 # this is called without 'env' by AdjustDefByDirectives transform before declaration analysis 909 if self.annotation and env and env.directives['annotation_typing'] and self.base_type.name is None: 910 arg_type = self.inject_type_from_annotations(env) 911 if arg_type is not None: 912 base_type = arg_type 913 return self.declarator.analyse(base_type, env, nonempty=nonempty) 914 else: 915 return self.name_declarator, self.type 916 917 def inject_type_from_annotations(self, env): 918 annotation = self.annotation 919 if not annotation: 920 return None 921 base_type, arg_type = analyse_type_annotation(annotation, env, assigned_value=self.default) 922 if base_type is not None: 923 self.base_type = base_type 924 return arg_type 925 926 def calculate_default_value_code(self, code): 927 if self.default_value is None: 928 if self.default: 929 if self.default.is_literal: 930 # will not output any code, just assign the result_code 931 self.default.generate_evaluation_code(code) 932 return self.type.cast_code(self.default.result()) 933 self.default_value = code.get_argument_default_const(self.type) 934 return self.default_value 935 936 def annotate(self, code): 937 if self.default: 938 self.default.annotate(code) 939 940 def generate_assignment_code(self, code, target=None, overloaded_assignment=False): 941 default = self.default 942 if default is None or default.is_literal: 943 return 944 if target is None: 945 target = self.calculate_default_value_code(code) 946 default.generate_evaluation_code(code) 947 default.make_owned_reference(code) 948 result = default.result() if overloaded_assignment else default.result_as(self.type) 949 code.putln("%s = %s;" % (target, result)) 950 if self.type.is_pyobject: 951 code.put_giveref(default.result()) 952 default.generate_post_assignment_code(code) 953 default.free_temps(code) 954 955 956class CBaseTypeNode(Node): 957 # Abstract base class for C base type nodes. 958 # 959 # Processing during analyse_declarations phase: 960 # 961 # analyse 962 # Returns the type. 963 964 def analyse_as_type(self, env): 965 return self.analyse(env) 966 967 968class CAnalysedBaseTypeNode(Node): 969 # type type 970 971 child_attrs = [] 972 973 def analyse(self, env, could_be_name=False): 974 return self.type 975 976 977class CSimpleBaseTypeNode(CBaseTypeNode): 978 # name string 979 # module_path [string] Qualifying name components 980 # is_basic_c_type boolean 981 # signed boolean 982 # longness integer 983 # complex boolean 984 # is_self_arg boolean Is self argument of C method 985 # ##is_type_arg boolean Is type argument of class method 986 987 child_attrs = [] 988 arg_name = None # in case the argument name was interpreted as a type 989 module_path = [] 990 is_basic_c_type = False 991 complex = False 992 993 def analyse(self, env, could_be_name=False): 994 # Return type descriptor. 995 #print "CSimpleBaseTypeNode.analyse: is_self_arg =", self.is_self_arg ### 996 type = None 997 if self.is_basic_c_type: 998 type = PyrexTypes.simple_c_type(self.signed, self.longness, self.name) 999 if not type: 1000 error(self.pos, "Unrecognised type modifier combination") 1001 elif self.name == "object" and not self.module_path: 1002 type = py_object_type 1003 elif self.name is None: 1004 if self.is_self_arg and env.is_c_class_scope: 1005 #print "CSimpleBaseTypeNode.analyse: defaulting to parent type" ### 1006 type = env.parent_type 1007 ## elif self.is_type_arg and env.is_c_class_scope: 1008 ## type = Builtin.type_type 1009 else: 1010 type = py_object_type 1011 else: 1012 if self.module_path: 1013 # Maybe it's a nested C++ class. 1014 scope = env 1015 for item in self.module_path: 1016 entry = scope.lookup(item) 1017 if entry is not None and entry.is_cpp_class: 1018 scope = entry.type.scope 1019 else: 1020 scope = None 1021 break 1022 1023 if scope is None: 1024 # Maybe it's a cimport. 1025 scope = env.find_imported_module(self.module_path, self.pos) 1026 else: 1027 scope = env 1028 1029 if scope: 1030 if scope.is_c_class_scope: 1031 scope = scope.global_scope() 1032 1033 type = scope.lookup_type(self.name) 1034 if type is not None: 1035 pass 1036 elif could_be_name: 1037 if self.is_self_arg and env.is_c_class_scope: 1038 type = env.parent_type 1039 ## elif self.is_type_arg and env.is_c_class_scope: 1040 ## type = Builtin.type_type 1041 else: 1042 type = py_object_type 1043 self.arg_name = EncodedString(self.name) 1044 else: 1045 if self.templates: 1046 if not self.name in self.templates: 1047 error(self.pos, "'%s' is not a type identifier" % self.name) 1048 type = PyrexTypes.TemplatePlaceholderType(self.name) 1049 else: 1050 error(self.pos, "'%s' is not a type identifier" % self.name) 1051 if type and type.is_fused and env.fused_to_specific: 1052 type = type.specialize(env.fused_to_specific) 1053 if self.complex: 1054 if not type.is_numeric or type.is_complex: 1055 error(self.pos, "can only complexify c numeric types") 1056 type = PyrexTypes.CComplexType(type) 1057 type.create_declaration_utility_code(env) 1058 elif type is Builtin.complex_type: 1059 # Special case: optimise builtin complex type into C's 1060 # double complex. The parser cannot do this (as for the 1061 # normal scalar types) as the user may have redeclared the 1062 # 'complex' type. Testing for the exact type here works. 1063 type = PyrexTypes.c_double_complex_type 1064 type.create_declaration_utility_code(env) 1065 self.complex = True 1066 if type: 1067 return type 1068 else: 1069 return PyrexTypes.error_type 1070 1071class MemoryViewSliceTypeNode(CBaseTypeNode): 1072 1073 name = 'memoryview' 1074 child_attrs = ['base_type_node', 'axes'] 1075 1076 def analyse(self, env, could_be_name=False): 1077 1078 base_type = self.base_type_node.analyse(env) 1079 if base_type.is_error: return base_type 1080 1081 from . import MemoryView 1082 1083 try: 1084 axes_specs = MemoryView.get_axes_specs(env, self.axes) 1085 except CompileError as e: 1086 error(e.position, e.message_only) 1087 self.type = PyrexTypes.ErrorType() 1088 return self.type 1089 1090 if not MemoryView.validate_axes(self.pos, axes_specs): 1091 self.type = error_type 1092 else: 1093 self.type = PyrexTypes.MemoryViewSliceType(base_type, axes_specs) 1094 self.type.validate_memslice_dtype(self.pos) 1095 self.use_memview_utilities(env) 1096 1097 return self.type 1098 1099 def use_memview_utilities(self, env): 1100 from . import MemoryView 1101 env.use_utility_code(MemoryView.view_utility_code) 1102 1103 1104class CNestedBaseTypeNode(CBaseTypeNode): 1105 # For C++ classes that live inside other C++ classes. 1106 1107 # name string 1108 # base_type CBaseTypeNode 1109 1110 child_attrs = ['base_type'] 1111 1112 def analyse(self, env, could_be_name=None): 1113 base_type = self.base_type.analyse(env) 1114 if base_type is PyrexTypes.error_type: 1115 return PyrexTypes.error_type 1116 if not base_type.is_cpp_class: 1117 error(self.pos, "'%s' is not a valid type scope" % base_type) 1118 return PyrexTypes.error_type 1119 type_entry = base_type.scope.lookup_here(self.name) 1120 if not type_entry or not type_entry.is_type: 1121 error(self.pos, "'%s.%s' is not a type identifier" % (base_type, self.name)) 1122 return PyrexTypes.error_type 1123 return type_entry.type 1124 1125 1126class TemplatedTypeNode(CBaseTypeNode): 1127 # After parsing: 1128 # positional_args [ExprNode] List of positional arguments 1129 # keyword_args DictNode Keyword arguments 1130 # base_type_node CBaseTypeNode 1131 1132 # After analysis: 1133 # type PyrexTypes.BufferType or PyrexTypes.CppClassType ...containing the right options 1134 1135 child_attrs = ["base_type_node", "positional_args", 1136 "keyword_args", "dtype_node"] 1137 1138 dtype_node = None 1139 1140 name = None 1141 1142 def analyse(self, env, could_be_name=False, base_type=None): 1143 if base_type is None: 1144 base_type = self.base_type_node.analyse(env) 1145 if base_type.is_error: return base_type 1146 1147 if base_type.is_cpp_class and base_type.is_template_type(): 1148 # Templated class 1149 if self.keyword_args and self.keyword_args.key_value_pairs: 1150 error(self.pos, "c++ templates cannot take keyword arguments") 1151 self.type = PyrexTypes.error_type 1152 else: 1153 template_types = [] 1154 for template_node in self.positional_args: 1155 type = template_node.analyse_as_type(env) 1156 if type is None: 1157 error(template_node.pos, "unknown type in template argument") 1158 type = error_type 1159 template_types.append(type) 1160 self.type = base_type.specialize_here(self.pos, template_types) 1161 1162 elif base_type.is_pyobject: 1163 # Buffer 1164 from . import Buffer 1165 1166 options = Buffer.analyse_buffer_options( 1167 self.pos, 1168 env, 1169 self.positional_args, 1170 self.keyword_args, 1171 base_type.buffer_defaults) 1172 1173 if sys.version_info[0] < 3: 1174 # Py 2.x enforces byte strings as keyword arguments ... 1175 options = dict([(name.encode('ASCII'), value) 1176 for name, value in options.items()]) 1177 1178 self.type = PyrexTypes.BufferType(base_type, **options) 1179 if has_np_pythran(env) and is_pythran_buffer(self.type): 1180 self.type = PyrexTypes.PythranExpr(pythran_type(self.type), self.type) 1181 1182 else: 1183 # Array 1184 empty_declarator = CNameDeclaratorNode(self.pos, name="", cname=None) 1185 if len(self.positional_args) > 1 or self.keyword_args.key_value_pairs: 1186 error(self.pos, "invalid array declaration") 1187 self.type = PyrexTypes.error_type 1188 else: 1189 # It would be nice to merge this class with CArrayDeclaratorNode, 1190 # but arrays are part of the declaration, not the type... 1191 if not self.positional_args: 1192 dimension = None 1193 else: 1194 dimension = self.positional_args[0] 1195 self.array_declarator = CArrayDeclaratorNode( 1196 self.pos, 1197 base=empty_declarator, 1198 dimension=dimension) 1199 self.type = self.array_declarator.analyse(base_type, env)[1] 1200 1201 if self.type.is_fused and env.fused_to_specific: 1202 self.type = self.type.specialize(env.fused_to_specific) 1203 1204 return self.type 1205 1206 1207class CComplexBaseTypeNode(CBaseTypeNode): 1208 # base_type CBaseTypeNode 1209 # declarator CDeclaratorNode 1210 1211 child_attrs = ["base_type", "declarator"] 1212 1213 def analyse(self, env, could_be_name=False): 1214 base = self.base_type.analyse(env, could_be_name) 1215 _, type = self.declarator.analyse(base, env) 1216 return type 1217 1218 1219class CTupleBaseTypeNode(CBaseTypeNode): 1220 # components [CBaseTypeNode] 1221 1222 child_attrs = ["components"] 1223 1224 def analyse(self, env, could_be_name=False): 1225 component_types = [] 1226 for c in self.components: 1227 type = c.analyse(env) 1228 if type.is_pyobject: 1229 error(c.pos, "Tuple types can't (yet) contain Python objects.") 1230 return error_type 1231 component_types.append(type) 1232 entry = env.declare_tuple_type(self.pos, component_types) 1233 entry.used = True 1234 return entry.type 1235 1236 1237class FusedTypeNode(CBaseTypeNode): 1238 """ 1239 Represents a fused type in a ctypedef statement: 1240 1241 ctypedef cython.fused_type(int, long, long long) integral 1242 1243 name str name of this fused type 1244 types [CSimpleBaseTypeNode] is the list of types to be fused 1245 """ 1246 1247 child_attrs = [] 1248 1249 def analyse_declarations(self, env): 1250 type = self.analyse(env) 1251 entry = env.declare_typedef(self.name, type, self.pos) 1252 1253 # Omit the typedef declaration that self.declarator would produce 1254 entry.in_cinclude = True 1255 1256 def analyse(self, env, could_be_name=False): 1257 types = [] 1258 for type_node in self.types: 1259 type = type_node.analyse_as_type(env) 1260 1261 if not type: 1262 error(type_node.pos, "Not a type") 1263 continue 1264 1265 if type in types: 1266 error(type_node.pos, "Type specified multiple times") 1267 else: 1268 types.append(type) 1269 1270 # if len(self.types) == 1: 1271 # return types[0] 1272 1273 return PyrexTypes.FusedType(types, name=self.name) 1274 1275 1276class CConstTypeNode(CBaseTypeNode): 1277 # base_type CBaseTypeNode 1278 1279 child_attrs = ["base_type"] 1280 1281 def analyse(self, env, could_be_name=False): 1282 base = self.base_type.analyse(env, could_be_name) 1283 if base.is_pyobject: 1284 error(self.pos, 1285 "Const base type cannot be a Python object") 1286 return PyrexTypes.c_const_type(base) 1287 1288 1289class CVarDefNode(StatNode): 1290 # C variable definition or forward/extern function declaration. 1291 # 1292 # visibility 'private' or 'public' or 'extern' 1293 # base_type CBaseTypeNode 1294 # declarators [CDeclaratorNode] 1295 # in_pxd boolean 1296 # api boolean 1297 # overridable boolean whether it is a cpdef 1298 # modifiers ['inline'] 1299 1300 # decorators [cython.locals(...)] or None 1301 # directive_locals { string : NameNode } locals defined by cython.locals(...) 1302 1303 child_attrs = ["base_type", "declarators"] 1304 1305 decorators = None 1306 directive_locals = None 1307 1308 def analyse_declarations(self, env, dest_scope=None): 1309 if self.directive_locals is None: 1310 self.directive_locals = {} 1311 if not dest_scope: 1312 dest_scope = env 1313 self.dest_scope = dest_scope 1314 1315 if self.declarators: 1316 templates = self.declarators[0].analyse_templates() 1317 else: 1318 templates = None 1319 if templates is not None: 1320 if self.visibility != 'extern': 1321 error(self.pos, "Only extern functions allowed") 1322 if len(self.declarators) > 1: 1323 error(self.declarators[1].pos, "Can't multiply declare template types") 1324 env = TemplateScope('func_template', env) 1325 env.directives = env.outer_scope.directives 1326 for template_param in templates: 1327 env.declare_type(template_param.name, template_param, self.pos) 1328 1329 base_type = self.base_type.analyse(env) 1330 1331 if base_type.is_fused and not self.in_pxd and (env.is_c_class_scope or 1332 env.is_module_scope): 1333 error(self.pos, "Fused types not allowed here") 1334 return error_type 1335 1336 self.entry = None 1337 visibility = self.visibility 1338 1339 for declarator in self.declarators: 1340 1341 if (len(self.declarators) > 1 1342 and not isinstance(declarator, CNameDeclaratorNode) 1343 and env.directives['warn.multiple_declarators']): 1344 warning( 1345 declarator.pos, 1346 "Non-trivial type declarators in shared declaration (e.g. mix of pointers and values). " 1347 "Each pointer declaration should be on its own line.", 1) 1348 1349 create_extern_wrapper = (self.overridable 1350 and self.visibility == 'extern' 1351 and env.is_module_scope) 1352 if create_extern_wrapper: 1353 declarator.overridable = False 1354 if isinstance(declarator, CFuncDeclaratorNode): 1355 name_declarator, type = declarator.analyse( 1356 base_type, env, directive_locals=self.directive_locals, visibility=visibility, in_pxd=self.in_pxd) 1357 else: 1358 name_declarator, type = declarator.analyse( 1359 base_type, env, visibility=visibility, in_pxd=self.in_pxd) 1360 if not type.is_complete(): 1361 if not (self.visibility == 'extern' and type.is_array or type.is_memoryviewslice): 1362 error(declarator.pos, "Variable type '%s' is incomplete" % type) 1363 if self.visibility == 'extern' and type.is_pyobject: 1364 error(declarator.pos, "Python object cannot be declared extern") 1365 name = name_declarator.name 1366 cname = name_declarator.cname 1367 if name == '': 1368 error(declarator.pos, "Missing name in declaration.") 1369 return 1370 if type.is_reference and self.visibility != 'extern': 1371 error(declarator.pos, "C++ references cannot be declared; use a pointer instead") 1372 if type.is_cfunction: 1373 if 'staticmethod' in env.directives: 1374 type.is_static_method = True 1375 self.entry = dest_scope.declare_cfunction( 1376 name, type, declarator.pos, 1377 cname=cname, visibility=self.visibility, in_pxd=self.in_pxd, 1378 api=self.api, modifiers=self.modifiers, overridable=self.overridable) 1379 if self.entry is not None: 1380 self.entry.directive_locals = copy.copy(self.directive_locals) 1381 if create_extern_wrapper: 1382 self.entry.type.create_to_py_utility_code(env) 1383 self.entry.create_wrapper = True 1384 else: 1385 if self.overridable: 1386 warning(self.pos, "cpdef variables will not be supported in Cython 3; " 1387 "currently they are no different from cdef variables", 2) 1388 if self.directive_locals: 1389 error(self.pos, "Decorators can only be followed by functions") 1390 self.entry = dest_scope.declare_var( 1391 name, type, declarator.pos, 1392 cname=cname, visibility=visibility, in_pxd=self.in_pxd, 1393 api=self.api, is_cdef=1) 1394 if Options.docstrings: 1395 self.entry.doc = embed_position(self.pos, self.doc) 1396 1397 1398class CStructOrUnionDefNode(StatNode): 1399 # name string 1400 # cname string or None 1401 # kind "struct" or "union" 1402 # typedef_flag boolean 1403 # visibility "public" or "private" 1404 # api boolean 1405 # in_pxd boolean 1406 # attributes [CVarDefNode] or None 1407 # entry Entry 1408 # packed boolean 1409 1410 child_attrs = ["attributes"] 1411 1412 def declare(self, env, scope=None): 1413 self.entry = env.declare_struct_or_union( 1414 self.name, self.kind, scope, self.typedef_flag, self.pos, 1415 self.cname, visibility=self.visibility, api=self.api, 1416 packed=self.packed) 1417 1418 def analyse_declarations(self, env): 1419 scope = None 1420 if self.attributes is not None: 1421 scope = StructOrUnionScope(self.name) 1422 self.declare(env, scope) 1423 if self.attributes is not None: 1424 if self.in_pxd and not env.in_cinclude: 1425 self.entry.defined_in_pxd = 1 1426 for attr in self.attributes: 1427 attr.analyse_declarations(env, scope) 1428 if self.visibility != 'extern': 1429 for attr in scope.var_entries: 1430 type = attr.type 1431 while type.is_array: 1432 type = type.base_type 1433 if type == self.entry.type: 1434 error(attr.pos, "Struct cannot contain itself as a member.") 1435 1436 def analyse_expressions(self, env): 1437 return self 1438 1439 def generate_execution_code(self, code): 1440 pass 1441 1442 1443class CppClassNode(CStructOrUnionDefNode, BlockNode): 1444 1445 # name string 1446 # cname string or None 1447 # visibility "extern" 1448 # in_pxd boolean 1449 # attributes [CVarDefNode] or None 1450 # entry Entry 1451 # base_classes [CBaseTypeNode] 1452 # templates [(string, bool)] or None 1453 # decorators [DecoratorNode] or None 1454 1455 decorators = None 1456 1457 def declare(self, env): 1458 if self.templates is None: 1459 template_types = None 1460 else: 1461 template_types = [PyrexTypes.TemplatePlaceholderType(template_name, not required) 1462 for template_name, required in self.templates] 1463 num_optional_templates = sum(not required for _, required in self.templates) 1464 if num_optional_templates and not all(required for _, required in self.templates[:-num_optional_templates]): 1465 error(self.pos, "Required template parameters must precede optional template parameters.") 1466 self.entry = env.declare_cpp_class( 1467 self.name, None, self.pos, self.cname, 1468 base_classes=[], visibility=self.visibility, templates=template_types) 1469 1470 def analyse_declarations(self, env): 1471 if self.templates is None: 1472 template_types = template_names = None 1473 else: 1474 template_names = [template_name for template_name, _ in self.templates] 1475 template_types = [PyrexTypes.TemplatePlaceholderType(template_name, not required) 1476 for template_name, required in self.templates] 1477 scope = None 1478 if self.attributes is not None: 1479 scope = CppClassScope(self.name, env, templates=template_names) 1480 def base_ok(base_class): 1481 if base_class.is_cpp_class or base_class.is_struct: 1482 return True 1483 else: 1484 error(self.pos, "Base class '%s' not a struct or class." % base_class) 1485 base_class_types = filter(base_ok, [b.analyse(scope or env) for b in self.base_classes]) 1486 self.entry = env.declare_cpp_class( 1487 self.name, scope, self.pos, 1488 self.cname, base_class_types, visibility=self.visibility, templates=template_types) 1489 if self.entry is None: 1490 return 1491 self.entry.is_cpp_class = 1 1492 if scope is not None: 1493 scope.type = self.entry.type 1494 defined_funcs = [] 1495 def func_attributes(attributes): 1496 for attr in attributes: 1497 if isinstance(attr, CFuncDefNode): 1498 yield attr 1499 elif isinstance(attr, CompilerDirectivesNode): 1500 for sub_attr in func_attributes(attr.body.stats): 1501 yield sub_attr 1502 if self.attributes is not None: 1503 if self.in_pxd and not env.in_cinclude: 1504 self.entry.defined_in_pxd = 1 1505 for attr in self.attributes: 1506 declare = getattr(attr, 'declare', None) 1507 if declare: 1508 attr.declare(scope) 1509 attr.analyse_declarations(scope) 1510 for func in func_attributes(self.attributes): 1511 defined_funcs.append(func) 1512 if self.templates is not None: 1513 func.template_declaration = "template <typename %s>" % ", typename ".join(template_names) 1514 self.body = StatListNode(self.pos, stats=defined_funcs) 1515 self.scope = scope 1516 1517 def analyse_expressions(self, env): 1518 self.body = self.body.analyse_expressions(self.entry.type.scope) 1519 return self 1520 1521 def generate_function_definitions(self, env, code): 1522 self.body.generate_function_definitions(self.entry.type.scope, code) 1523 1524 def generate_execution_code(self, code): 1525 self.body.generate_execution_code(code) 1526 1527 def annotate(self, code): 1528 self.body.annotate(code) 1529 1530 1531class CEnumDefNode(StatNode): 1532 # name string or None 1533 # cname string or None 1534 # items [CEnumDefItemNode] 1535 # typedef_flag boolean 1536 # visibility "public" or "private" or "extern" 1537 # api boolean 1538 # in_pxd boolean 1539 # create_wrapper boolean 1540 # entry Entry 1541 1542 child_attrs = ["items"] 1543 1544 def declare(self, env): 1545 self.entry = env.declare_enum( 1546 self.name, self.pos, 1547 cname=self.cname, typedef_flag=self.typedef_flag, 1548 visibility=self.visibility, api=self.api, 1549 create_wrapper=self.create_wrapper) 1550 1551 def analyse_declarations(self, env): 1552 if self.items is not None: 1553 if self.in_pxd and not env.in_cinclude: 1554 self.entry.defined_in_pxd = 1 1555 for item in self.items: 1556 item.analyse_declarations(env, self.entry) 1557 1558 def analyse_expressions(self, env): 1559 return self 1560 1561 def generate_execution_code(self, code): 1562 if self.visibility == 'public' or self.api: 1563 code.mark_pos(self.pos) 1564 temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True) 1565 for item in self.entry.enum_values: 1566 code.putln("%s = PyInt_FromLong(%s); %s" % ( 1567 temp, 1568 item.cname, 1569 code.error_goto_if_null(temp, item.pos))) 1570 code.put_gotref(temp) 1571 code.putln('if (PyDict_SetItemString(%s, "%s", %s) < 0) %s' % ( 1572 Naming.moddict_cname, 1573 item.name, 1574 temp, 1575 code.error_goto(item.pos))) 1576 code.put_decref_clear(temp, PyrexTypes.py_object_type) 1577 code.funcstate.release_temp(temp) 1578 1579 1580class CEnumDefItemNode(StatNode): 1581 # name string 1582 # cname string or None 1583 # value ExprNode or None 1584 1585 child_attrs = ["value"] 1586 1587 def analyse_declarations(self, env, enum_entry): 1588 if self.value: 1589 self.value = self.value.analyse_const_expression(env) 1590 if not self.value.type.is_int: 1591 self.value = self.value.coerce_to(PyrexTypes.c_int_type, env) 1592 self.value = self.value.analyse_const_expression(env) 1593 entry = env.declare_const( 1594 self.name, enum_entry.type, 1595 self.value, self.pos, cname=self.cname, 1596 visibility=enum_entry.visibility, api=enum_entry.api, 1597 create_wrapper=enum_entry.create_wrapper and enum_entry.name is None) 1598 enum_entry.enum_values.append(entry) 1599 if enum_entry.name: 1600 enum_entry.type.values.append(entry.name) 1601 1602 1603class CTypeDefNode(StatNode): 1604 # base_type CBaseTypeNode 1605 # declarator CDeclaratorNode 1606 # visibility "public" or "private" 1607 # api boolean 1608 # in_pxd boolean 1609 1610 child_attrs = ["base_type", "declarator"] 1611 1612 def analyse_declarations(self, env): 1613 base = self.base_type.analyse(env) 1614 name_declarator, type = self.declarator.analyse( 1615 base, env, visibility=self.visibility, in_pxd=self.in_pxd) 1616 name = name_declarator.name 1617 cname = name_declarator.cname 1618 1619 entry = env.declare_typedef( 1620 name, type, self.pos, 1621 cname=cname, visibility=self.visibility, api=self.api) 1622 1623 if type.is_fused: 1624 entry.in_cinclude = True 1625 1626 if self.in_pxd and not env.in_cinclude: 1627 entry.defined_in_pxd = 1 1628 1629 def analyse_expressions(self, env): 1630 return self 1631 1632 def generate_execution_code(self, code): 1633 pass 1634 1635 1636class FuncDefNode(StatNode, BlockNode): 1637 # Base class for function definition nodes. 1638 # 1639 # return_type PyrexType 1640 # #filename string C name of filename string const 1641 # entry Symtab.Entry 1642 # needs_closure boolean Whether or not this function has inner functions/classes/yield 1643 # needs_outer_scope boolean Whether or not this function requires outer scope 1644 # pymethdef_required boolean Force Python method struct generation 1645 # directive_locals { string : ExprNode } locals defined by cython.locals(...) 1646 # directive_returns [ExprNode] type defined by cython.returns(...) 1647 # star_arg PyArgDeclNode or None * argument 1648 # starstar_arg PyArgDeclNode or None ** argument 1649 # 1650 # is_async_def boolean is a Coroutine function 1651 # 1652 # has_fused_arguments boolean 1653 # Whether this cdef function has fused parameters. This is needed 1654 # by AnalyseDeclarationsTransform, so it can replace CFuncDefNodes 1655 # with fused argument types with a FusedCFuncDefNode 1656 1657 py_func = None 1658 needs_closure = False 1659 needs_outer_scope = False 1660 pymethdef_required = False 1661 is_generator = False 1662 is_generator_body = False 1663 is_async_def = False 1664 modifiers = [] 1665 has_fused_arguments = False 1666 star_arg = None 1667 starstar_arg = None 1668 is_cyfunction = False 1669 code_object = None 1670 1671 def analyse_default_values(self, env): 1672 default_seen = 0 1673 for arg in self.args: 1674 if arg.default: 1675 default_seen = 1 1676 if arg.is_generic: 1677 arg.default = arg.default.analyse_types(env) 1678 arg.default = arg.default.coerce_to(arg.type, env) 1679 else: 1680 error(arg.pos, "This argument cannot have a default value") 1681 arg.default = None 1682 elif arg.kw_only: 1683 default_seen = 1 1684 elif default_seen: 1685 error(arg.pos, "Non-default argument following default argument") 1686 1687 def analyse_annotation(self, env, annotation): 1688 # Annotations can not only contain valid Python expressions but arbitrary type references. 1689 if annotation is None: 1690 return None 1691 if not env.directives['annotation_typing'] or annotation.analyse_as_type(env) is None: 1692 annotation = annotation.analyse_types(env) 1693 return annotation 1694 1695 def analyse_annotations(self, env): 1696 for arg in self.args: 1697 if arg.annotation: 1698 arg.annotation = self.analyse_annotation(env, arg.annotation) 1699 1700 def align_argument_type(self, env, arg): 1701 # @cython.locals() 1702 directive_locals = self.directive_locals 1703 orig_type = arg.type 1704 if arg.name in directive_locals: 1705 type_node = directive_locals[arg.name] 1706 other_type = type_node.analyse_as_type(env) 1707 elif isinstance(arg, CArgDeclNode) and arg.annotation and env.directives['annotation_typing']: 1708 type_node = arg.annotation 1709 other_type = arg.inject_type_from_annotations(env) 1710 if other_type is None: 1711 return arg 1712 else: 1713 return arg 1714 if other_type is None: 1715 error(type_node.pos, "Not a type") 1716 elif orig_type is not py_object_type and not orig_type.same_as(other_type): 1717 error(arg.base_type.pos, "Signature does not agree with previous declaration") 1718 error(type_node.pos, "Previous declaration here") 1719 else: 1720 arg.type = other_type 1721 return arg 1722 1723 def need_gil_acquisition(self, lenv): 1724 return 0 1725 1726 def create_local_scope(self, env): 1727 genv = env 1728 while genv.is_py_class_scope or genv.is_c_class_scope: 1729 genv = genv.outer_scope 1730 if self.needs_closure: 1731 lenv = ClosureScope(name=self.entry.name, 1732 outer_scope=genv, 1733 parent_scope=env, 1734 scope_name=self.entry.cname) 1735 else: 1736 lenv = LocalScope(name=self.entry.name, 1737 outer_scope=genv, 1738 parent_scope=env) 1739 lenv.return_type = self.return_type 1740 type = self.entry.type 1741 if type.is_cfunction: 1742 lenv.nogil = type.nogil and not type.with_gil 1743 self.local_scope = lenv 1744 lenv.directives = env.directives 1745 return lenv 1746 1747 def generate_function_body(self, env, code): 1748 self.body.generate_execution_code(code) 1749 1750 def generate_function_definitions(self, env, code): 1751 from . import Buffer 1752 if self.return_type.is_memoryviewslice: 1753 from . import MemoryView 1754 1755 lenv = self.local_scope 1756 if lenv.is_closure_scope and not lenv.is_passthrough: 1757 outer_scope_cname = "%s->%s" % (Naming.cur_scope_cname, 1758 Naming.outer_scope_cname) 1759 else: 1760 outer_scope_cname = Naming.outer_scope_cname 1761 lenv.mangle_closure_cnames(outer_scope_cname) 1762 # Generate closure function definitions 1763 self.body.generate_function_definitions(lenv, code) 1764 # generate lambda function definitions 1765 self.generate_lambda_definitions(lenv, code) 1766 1767 is_getbuffer_slot = (self.entry.name == "__getbuffer__" and 1768 self.entry.scope.is_c_class_scope) 1769 is_releasebuffer_slot = (self.entry.name == "__releasebuffer__" and 1770 self.entry.scope.is_c_class_scope) 1771 is_buffer_slot = is_getbuffer_slot or is_releasebuffer_slot 1772 if is_buffer_slot: 1773 if 'cython_unused' not in self.modifiers: 1774 self.modifiers = self.modifiers + ['cython_unused'] 1775 1776 preprocessor_guard = self.get_preprocessor_guard() 1777 1778 profile = code.globalstate.directives['profile'] 1779 linetrace = code.globalstate.directives['linetrace'] 1780 if profile or linetrace: 1781 code.globalstate.use_utility_code( 1782 UtilityCode.load_cached("Profile", "Profile.c")) 1783 1784 # Generate C code for header and body of function 1785 code.enter_cfunc_scope(lenv) 1786 code.return_from_error_cleanup_label = code.new_label() 1787 code.funcstate.gil_owned = not lenv.nogil 1788 1789 # ----- Top-level constants used by this function 1790 code.mark_pos(self.pos) 1791 self.generate_cached_builtins_decls(lenv, code) 1792 # ----- Function header 1793 code.putln("") 1794 1795 if preprocessor_guard: 1796 code.putln(preprocessor_guard) 1797 1798 with_pymethdef = (self.needs_assignment_synthesis(env, code) or 1799 self.pymethdef_required) 1800 if self.py_func: 1801 self.py_func.generate_function_header( 1802 code, with_pymethdef=with_pymethdef, proto_only=True) 1803 self.generate_function_header(code, with_pymethdef=with_pymethdef) 1804 # ----- Local variable declarations 1805 # Find function scope 1806 cenv = env 1807 while cenv.is_py_class_scope or cenv.is_c_class_scope: 1808 cenv = cenv.outer_scope 1809 if self.needs_closure: 1810 code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname)) 1811 code.putln(";") 1812 elif self.needs_outer_scope: 1813 if lenv.is_passthrough: 1814 code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname)) 1815 code.putln(";") 1816 code.put(cenv.scope_class.type.declaration_code(Naming.outer_scope_cname)) 1817 code.putln(";") 1818 self.generate_argument_declarations(lenv, code) 1819 1820 for entry in lenv.var_entries: 1821 if not (entry.in_closure or entry.is_arg): 1822 code.put_var_declaration(entry) 1823 1824 # Initialize the return variable __pyx_r 1825 init = "" 1826 if not self.return_type.is_void: 1827 if self.return_type.is_pyobject: 1828 init = " = NULL" 1829 elif self.return_type.is_memoryviewslice: 1830 init = ' = ' + MemoryView.memslice_entry_init 1831 1832 code.putln("%s%s;" % ( 1833 self.return_type.declaration_code(Naming.retval_cname), 1834 init)) 1835 1836 tempvardecl_code = code.insertion_point() 1837 self.generate_keyword_list(code) 1838 1839 # ----- GIL acquisition 1840 acquire_gil = self.acquire_gil 1841 1842 # See if we need to acquire the GIL for variable declarations, or for 1843 # refnanny only 1844 1845 # Closures are not currently possible for cdef nogil functions, 1846 # but check them anyway 1847 have_object_args = self.needs_closure or self.needs_outer_scope 1848 for arg in lenv.arg_entries: 1849 if arg.type.is_pyobject: 1850 have_object_args = True 1851 break 1852 1853 used_buffer_entries = [entry for entry in lenv.buffer_entries if entry.used] 1854 1855 acquire_gil_for_var_decls_only = ( 1856 lenv.nogil and lenv.has_with_gil_block and 1857 (have_object_args or used_buffer_entries)) 1858 1859 acquire_gil_for_refnanny_only = ( 1860 lenv.nogil and lenv.has_with_gil_block and not 1861 acquire_gil_for_var_decls_only) 1862 1863 use_refnanny = not lenv.nogil or lenv.has_with_gil_block 1864 1865 if acquire_gil or acquire_gil_for_var_decls_only: 1866 code.put_ensure_gil() 1867 code.funcstate.gil_owned = True 1868 elif lenv.nogil and lenv.has_with_gil_block: 1869 code.declare_gilstate() 1870 1871 if profile or linetrace: 1872 if not self.is_generator: 1873 # generators are traced when iterated, not at creation 1874 tempvardecl_code.put_trace_declarations() 1875 code_object = self.code_object.calculate_result_code(code) if self.code_object else None 1876 code.put_trace_frame_init(code_object) 1877 1878 # ----- Special check for getbuffer 1879 if is_getbuffer_slot: 1880 self.getbuffer_check(code) 1881 1882 # ----- set up refnanny 1883 if use_refnanny: 1884 tempvardecl_code.put_declare_refcount_context() 1885 code.put_setup_refcount_context( 1886 self.entry.name, acquire_gil=acquire_gil_for_refnanny_only) 1887 1888 # ----- Automatic lead-ins for certain special functions 1889 if is_getbuffer_slot: 1890 self.getbuffer_init(code) 1891 # ----- Create closure scope object 1892 if self.needs_closure: 1893 tp_slot = TypeSlots.ConstructorSlot("tp_new", '__new__') 1894 slot_func_cname = TypeSlots.get_slot_function(lenv.scope_class.type.scope, tp_slot) 1895 if not slot_func_cname: 1896 slot_func_cname = '%s->tp_new' % lenv.scope_class.type.typeptr_cname 1897 code.putln("%s = (%s)%s(%s, %s, NULL);" % ( 1898 Naming.cur_scope_cname, 1899 lenv.scope_class.type.empty_declaration_code(), 1900 slot_func_cname, 1901 lenv.scope_class.type.typeptr_cname, 1902 Naming.empty_tuple)) 1903 code.putln("if (unlikely(!%s)) {" % Naming.cur_scope_cname) 1904 # Scope unconditionally DECREFed on return. 1905 code.putln("%s = %s;" % ( 1906 Naming.cur_scope_cname, 1907 lenv.scope_class.type.cast_code("Py_None"))) 1908 code.put_incref("Py_None", py_object_type) 1909 code.putln(code.error_goto(self.pos)) 1910 code.putln("} else {") 1911 code.put_gotref(Naming.cur_scope_cname) 1912 code.putln("}") 1913 # Note that it is unsafe to decref the scope at this point. 1914 if self.needs_outer_scope: 1915 if self.is_cyfunction: 1916 code.putln("%s = (%s) __Pyx_CyFunction_GetClosure(%s);" % ( 1917 outer_scope_cname, 1918 cenv.scope_class.type.empty_declaration_code(), 1919 Naming.self_cname)) 1920 else: 1921 code.putln("%s = (%s) %s;" % ( 1922 outer_scope_cname, 1923 cenv.scope_class.type.empty_declaration_code(), 1924 Naming.self_cname)) 1925 if lenv.is_passthrough: 1926 code.putln("%s = %s;" % (Naming.cur_scope_cname, outer_scope_cname)) 1927 elif self.needs_closure: 1928 # inner closures own a reference to their outer parent 1929 code.put_incref(outer_scope_cname, cenv.scope_class.type) 1930 code.put_giveref(outer_scope_cname) 1931 # ----- Trace function call 1932 if profile or linetrace: 1933 # this looks a bit late, but if we don't get here due to a 1934 # fatal error before hand, it's not really worth tracing 1935 if not self.is_generator: 1936 # generators are traced when iterated, not at creation 1937 if self.is_wrapper: 1938 trace_name = self.entry.name + " (wrapper)" 1939 else: 1940 trace_name = self.entry.name 1941 code.put_trace_call( 1942 trace_name, self.pos, nogil=not code.funcstate.gil_owned) 1943 code.funcstate.can_trace = True 1944 # ----- Fetch arguments 1945 self.generate_argument_parsing_code(env, code) 1946 # If an argument is assigned to in the body, we must 1947 # incref it to properly keep track of refcounts. 1948 is_cdef = isinstance(self, CFuncDefNode) 1949 for entry in lenv.arg_entries: 1950 if entry.type.is_pyobject: 1951 if (acquire_gil or len(entry.cf_assignments) > 1) and not entry.in_closure: 1952 code.put_var_incref(entry) 1953 1954 # Note: defaults are always incref-ed. For def functions, we 1955 # we acquire arguments from object conversion, so we have 1956 # new references. If we are a cdef function, we need to 1957 # incref our arguments 1958 elif is_cdef and entry.type.is_memoryviewslice and len(entry.cf_assignments) > 1: 1959 code.put_incref_memoryviewslice(entry.cname, have_gil=code.funcstate.gil_owned) 1960 for entry in lenv.var_entries: 1961 if entry.is_arg and len(entry.cf_assignments) > 1 and not entry.in_closure: 1962 if entry.xdecref_cleanup: 1963 code.put_var_xincref(entry) 1964 else: 1965 code.put_var_incref(entry) 1966 1967 # ----- Initialise local buffer auxiliary variables 1968 for entry in lenv.var_entries + lenv.arg_entries: 1969 if entry.type.is_buffer and entry.buffer_aux.buflocal_nd_var.used: 1970 Buffer.put_init_vars(entry, code) 1971 1972 # ----- Check and convert arguments 1973 self.generate_argument_type_tests(code) 1974 # ----- Acquire buffer arguments 1975 for entry in lenv.arg_entries: 1976 if entry.type.is_buffer: 1977 Buffer.put_acquire_arg_buffer(entry, code, self.pos) 1978 1979 if acquire_gil_for_var_decls_only: 1980 code.put_release_ensured_gil() 1981 code.funcstate.gil_owned = False 1982 1983 # ------------------------- 1984 # ----- Function body ----- 1985 # ------------------------- 1986 self.generate_function_body(env, code) 1987 1988 code.mark_pos(self.pos, trace=False) 1989 code.putln("") 1990 code.putln("/* function exit code */") 1991 1992 # ----- Default return value 1993 if not self.body.is_terminator: 1994 if self.return_type.is_pyobject: 1995 #if self.return_type.is_extension_type: 1996 # lhs = "(PyObject *)%s" % Naming.retval_cname 1997 #else: 1998 lhs = Naming.retval_cname 1999 code.put_init_to_py_none(lhs, self.return_type) 2000 else: 2001 val = self.return_type.default_value 2002 if val: 2003 code.putln("%s = %s;" % (Naming.retval_cname, val)) 2004 elif not self.return_type.is_void: 2005 code.putln("__Pyx_pretend_to_initialize(&%s);" % Naming.retval_cname) 2006 # ----- Error cleanup 2007 if code.error_label in code.labels_used: 2008 if not self.body.is_terminator: 2009 code.put_goto(code.return_label) 2010 code.put_label(code.error_label) 2011 for cname, type in code.funcstate.all_managed_temps(): 2012 code.put_xdecref(cname, type, have_gil=not lenv.nogil) 2013 2014 # Clean up buffers -- this calls a Python function 2015 # so need to save and restore error state 2016 buffers_present = len(used_buffer_entries) > 0 2017 #memslice_entries = [e for e in lenv.entries.values() if e.type.is_memoryviewslice] 2018 if buffers_present: 2019 code.globalstate.use_utility_code(restore_exception_utility_code) 2020 code.putln("{ PyObject *__pyx_type, *__pyx_value, *__pyx_tb;") 2021 code.putln("__Pyx_PyThreadState_declare") 2022 code.putln("__Pyx_PyThreadState_assign") 2023 code.putln("__Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);") 2024 for entry in used_buffer_entries: 2025 Buffer.put_release_buffer_code(code, entry) 2026 #code.putln("%s = 0;" % entry.cname) 2027 code.putln("__Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}") 2028 2029 if self.return_type.is_memoryviewslice: 2030 MemoryView.put_init_entry(Naming.retval_cname, code) 2031 err_val = Naming.retval_cname 2032 else: 2033 err_val = self.error_value() 2034 2035 exc_check = self.caller_will_check_exceptions() 2036 if err_val is not None or exc_check: 2037 # TODO: Fix exception tracing (though currently unused by cProfile). 2038 # code.globalstate.use_utility_code(get_exception_tuple_utility_code) 2039 # code.put_trace_exception() 2040 2041 if lenv.nogil and not lenv.has_with_gil_block: 2042 code.putln("{") 2043 code.put_ensure_gil() 2044 2045 code.put_add_traceback(self.entry.qualified_name) 2046 2047 if lenv.nogil and not lenv.has_with_gil_block: 2048 code.put_release_ensured_gil() 2049 code.putln("}") 2050 else: 2051 warning(self.entry.pos, 2052 "Unraisable exception in function '%s'." % 2053 self.entry.qualified_name, 0) 2054 code.put_unraisable(self.entry.qualified_name, lenv.nogil) 2055 default_retval = self.return_type.default_value 2056 if err_val is None and default_retval: 2057 err_val = default_retval 2058 if err_val is not None: 2059 if err_val != Naming.retval_cname: 2060 code.putln("%s = %s;" % (Naming.retval_cname, err_val)) 2061 elif not self.return_type.is_void: 2062 code.putln("__Pyx_pretend_to_initialize(&%s);" % Naming.retval_cname) 2063 2064 if is_getbuffer_slot: 2065 self.getbuffer_error_cleanup(code) 2066 2067 # If we are using the non-error cleanup section we should 2068 # jump past it if we have an error. The if-test below determine 2069 # whether this section is used. 2070 if buffers_present or is_getbuffer_slot or self.return_type.is_memoryviewslice: 2071 code.put_goto(code.return_from_error_cleanup_label) 2072 2073 # ----- Non-error return cleanup 2074 code.put_label(code.return_label) 2075 for entry in used_buffer_entries: 2076 Buffer.put_release_buffer_code(code, entry) 2077 if is_getbuffer_slot: 2078 self.getbuffer_normal_cleanup(code) 2079 2080 if self.return_type.is_memoryviewslice: 2081 # See if our return value is uninitialized on non-error return 2082 # from . import MemoryView 2083 # MemoryView.err_if_nogil_initialized_check(self.pos, env) 2084 cond = code.unlikely(self.return_type.error_condition(Naming.retval_cname)) 2085 code.putln( 2086 'if (%s) {' % cond) 2087 if env.nogil: 2088 code.put_ensure_gil() 2089 code.putln( 2090 'PyErr_SetString(PyExc_TypeError, "Memoryview return value is not initialized");') 2091 if env.nogil: 2092 code.put_release_ensured_gil() 2093 code.putln( 2094 '}') 2095 2096 # ----- Return cleanup for both error and no-error return 2097 code.put_label(code.return_from_error_cleanup_label) 2098 2099 for entry in lenv.var_entries: 2100 if not entry.used or entry.in_closure: 2101 continue 2102 2103 if entry.type.is_memoryviewslice: 2104 code.put_xdecref_memoryviewslice(entry.cname, have_gil=not lenv.nogil) 2105 elif entry.type.is_pyobject: 2106 if not entry.is_arg or len(entry.cf_assignments) > 1: 2107 if entry.xdecref_cleanup: 2108 code.put_var_xdecref(entry) 2109 else: 2110 code.put_var_decref(entry) 2111 2112 # Decref any increfed args 2113 for entry in lenv.arg_entries: 2114 if entry.type.is_pyobject: 2115 if (acquire_gil or len(entry.cf_assignments) > 1) and not entry.in_closure: 2116 code.put_var_decref(entry) 2117 elif (entry.type.is_memoryviewslice and 2118 (not is_cdef or len(entry.cf_assignments) > 1)): 2119 # decref slices of def functions and acquired slices from cdef 2120 # functions, but not borrowed slices from cdef functions. 2121 code.put_xdecref_memoryviewslice(entry.cname, 2122 have_gil=not lenv.nogil) 2123 if self.needs_closure: 2124 code.put_decref(Naming.cur_scope_cname, lenv.scope_class.type) 2125 2126 # ----- Return 2127 # This code is duplicated in ModuleNode.generate_module_init_func 2128 if not lenv.nogil: 2129 default_retval = self.return_type.default_value 2130 err_val = self.error_value() 2131 if err_val is None and default_retval: 2132 err_val = default_retval # FIXME: why is err_val not used? 2133 if self.return_type.is_pyobject: 2134 code.put_xgiveref(self.return_type.as_pyobject(Naming.retval_cname)) 2135 2136 if self.entry.is_special and self.entry.name == "__hash__": 2137 # Returning -1 for __hash__ is supposed to signal an error 2138 # We do as Python instances and coerce -1 into -2. 2139 code.putln("if (unlikely(%s == -1) && !PyErr_Occurred()) %s = -2;" % ( 2140 Naming.retval_cname, Naming.retval_cname)) 2141 2142 if profile or linetrace: 2143 code.funcstate.can_trace = False 2144 if not self.is_generator: 2145 # generators are traced when iterated, not at creation 2146 if self.return_type.is_pyobject: 2147 code.put_trace_return( 2148 Naming.retval_cname, nogil=not code.funcstate.gil_owned) 2149 else: 2150 code.put_trace_return( 2151 "Py_None", nogil=not code.funcstate.gil_owned) 2152 2153 if not lenv.nogil: 2154 # GIL holding function 2155 code.put_finish_refcount_context() 2156 2157 if acquire_gil or (lenv.nogil and lenv.has_with_gil_block): 2158 # release the GIL (note that with-gil blocks acquire it on exit in their EnsureGILNode) 2159 code.put_release_ensured_gil() 2160 code.funcstate.gil_owned = False 2161 2162 if not self.return_type.is_void: 2163 code.putln("return %s;" % Naming.retval_cname) 2164 2165 code.putln("}") 2166 2167 if preprocessor_guard: 2168 code.putln("#endif /*!(%s)*/" % preprocessor_guard) 2169 2170 # ----- Go back and insert temp variable declarations 2171 tempvardecl_code.put_temp_declarations(code.funcstate) 2172 2173 # ----- Python version 2174 code.exit_cfunc_scope() 2175 if self.py_func: 2176 self.py_func.generate_function_definitions(env, code) 2177 self.generate_wrapper_functions(code) 2178 2179 def declare_argument(self, env, arg): 2180 if arg.type.is_void: 2181 error(arg.pos, "Invalid use of 'void'") 2182 elif not arg.type.is_complete() and not (arg.type.is_array or arg.type.is_memoryviewslice): 2183 error(arg.pos, "Argument type '%s' is incomplete" % arg.type) 2184 entry = env.declare_arg(arg.name, arg.type, arg.pos) 2185 if arg.annotation: 2186 entry.annotation = arg.annotation 2187 return entry 2188 2189 def generate_arg_type_test(self, arg, code): 2190 # Generate type test for one argument. 2191 if arg.type.typeobj_is_available(): 2192 code.globalstate.use_utility_code( 2193 UtilityCode.load_cached("ArgTypeTest", "FunctionArguments.c")) 2194 typeptr_cname = arg.type.typeptr_cname 2195 arg_code = "((PyObject *)%s)" % arg.entry.cname 2196 code.putln( 2197 'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % ( 2198 arg_code, 2199 typeptr_cname, 2200 arg.accept_none, 2201 arg.name, 2202 arg.type.is_builtin_type and arg.type.require_exact, 2203 code.error_goto(arg.pos))) 2204 else: 2205 error(arg.pos, "Cannot test type of extern C class without type object name specification") 2206 2207 def generate_arg_none_check(self, arg, code): 2208 # Generate None check for one argument. 2209 if arg.type.is_memoryviewslice: 2210 cname = "%s.memview" % arg.entry.cname 2211 else: 2212 cname = arg.entry.cname 2213 2214 code.putln('if (unlikely(((PyObject *)%s) == Py_None)) {' % cname) 2215 code.putln('''PyErr_Format(PyExc_TypeError, "Argument '%%.%ds' must not be None", "%s"); %s''' % ( 2216 max(200, len(arg.name)), arg.name, 2217 code.error_goto(arg.pos))) 2218 code.putln('}') 2219 2220 def generate_wrapper_functions(self, code): 2221 pass 2222 2223 def generate_execution_code(self, code): 2224 code.mark_pos(self.pos) 2225 # Evaluate and store argument default values 2226 for arg in self.args: 2227 if not arg.is_dynamic: 2228 arg.generate_assignment_code(code) 2229 2230 # 2231 # Special code for the __getbuffer__ function 2232 # 2233 def _get_py_buffer_info(self): 2234 py_buffer = self.local_scope.arg_entries[1] 2235 try: 2236 # Check builtin definition of struct Py_buffer 2237 obj_type = py_buffer.type.base_type.scope.entries['obj'].type 2238 except (AttributeError, KeyError): 2239 # User code redeclared struct Py_buffer 2240 obj_type = None 2241 return py_buffer, obj_type 2242 2243 # Old Python 3 used to support write-locks on buffer-like objects by 2244 # calling PyObject_GetBuffer() with a view==NULL parameter. This obscure 2245 # feature is obsolete, it was almost never used (only one instance in 2246 # `Modules/posixmodule.c` in Python 3.1) and it is now officially removed 2247 # (see bpo-14203). We add an extra check here to prevent legacy code from 2248 # from trying to use the feature and prevent segmentation faults. 2249 def getbuffer_check(self, code): 2250 py_buffer, _ = self._get_py_buffer_info() 2251 view = py_buffer.cname 2252 code.putln("if (%s == NULL) {" % view) 2253 code.putln("PyErr_SetString(PyExc_BufferError, " 2254 "\"PyObject_GetBuffer: view==NULL argument is obsolete\");") 2255 code.putln("return -1;") 2256 code.putln("}") 2257 2258 def getbuffer_init(self, code): 2259 py_buffer, obj_type = self._get_py_buffer_info() 2260 view = py_buffer.cname 2261 if obj_type and obj_type.is_pyobject: 2262 code.put_init_to_py_none("%s->obj" % view, obj_type) 2263 code.put_giveref("%s->obj" % view) # Do not refnanny object within structs 2264 else: 2265 code.putln("%s->obj = NULL;" % view) 2266 2267 def getbuffer_error_cleanup(self, code): 2268 py_buffer, obj_type = self._get_py_buffer_info() 2269 view = py_buffer.cname 2270 if obj_type and obj_type.is_pyobject: 2271 code.putln("if (%s->obj != NULL) {" % view) 2272 code.put_gotref("%s->obj" % view) 2273 code.put_decref_clear("%s->obj" % view, obj_type) 2274 code.putln("}") 2275 else: 2276 code.putln("Py_CLEAR(%s->obj);" % view) 2277 2278 def getbuffer_normal_cleanup(self, code): 2279 py_buffer, obj_type = self._get_py_buffer_info() 2280 view = py_buffer.cname 2281 if obj_type and obj_type.is_pyobject: 2282 code.putln("if (%s->obj == Py_None) {" % view) 2283 code.put_gotref("%s->obj" % view) 2284 code.put_decref_clear("%s->obj" % view, obj_type) 2285 code.putln("}") 2286 2287 def get_preprocessor_guard(self): 2288 if not self.entry.is_special: 2289 return None 2290 name = self.entry.name 2291 slot = TypeSlots.method_name_to_slot.get(name) 2292 if not slot: 2293 return None 2294 if name == '__long__' and not self.entry.scope.lookup_here('__int__'): 2295 return None 2296 if name in ("__getbuffer__", "__releasebuffer__") and self.entry.scope.is_c_class_scope: 2297 return None 2298 return slot.preprocessor_guard_code() 2299 2300 2301class CFuncDefNode(FuncDefNode): 2302 # C function definition. 2303 # 2304 # modifiers ['inline'] 2305 # visibility 'private' or 'public' or 'extern' 2306 # base_type CBaseTypeNode 2307 # declarator CDeclaratorNode 2308 # cfunc_declarator the CFuncDeclarator of this function 2309 # (this is also available through declarator or a 2310 # base thereof) 2311 # body StatListNode 2312 # api boolean 2313 # decorators [DecoratorNode] list of decorators 2314 # 2315 # with_gil boolean Acquire GIL around body 2316 # type CFuncType 2317 # py_func wrapper for calling from Python 2318 # overridable whether or not this is a cpdef function 2319 # inline_in_pxd whether this is an inline function in a pxd file 2320 # template_declaration String or None Used for c++ class methods 2321 # is_const_method whether this is a const method 2322 # is_static_method whether this is a static method 2323 # is_c_class_method whether this is a cclass method 2324 2325 child_attrs = ["base_type", "declarator", "body", "py_func_stat"] 2326 2327 inline_in_pxd = False 2328 decorators = None 2329 directive_locals = None 2330 directive_returns = None 2331 override = None 2332 template_declaration = None 2333 is_const_method = False 2334 py_func_stat = None 2335 2336 def unqualified_name(self): 2337 return self.entry.name 2338 2339 @property 2340 def code_object(self): 2341 # share the CodeObject with the cpdef wrapper (if available) 2342 return self.py_func.code_object if self.py_func else None 2343 2344 def analyse_declarations(self, env): 2345 self.is_c_class_method = env.is_c_class_scope 2346 if self.directive_locals is None: 2347 self.directive_locals = {} 2348 self.directive_locals.update(env.directives.get('locals', {})) 2349 if self.directive_returns is not None: 2350 base_type = self.directive_returns.analyse_as_type(env) 2351 if base_type is None: 2352 error(self.directive_returns.pos, "Not a type") 2353 base_type = PyrexTypes.error_type 2354 else: 2355 base_type = self.base_type.analyse(env) 2356 self.is_static_method = 'staticmethod' in env.directives and not env.lookup_here('staticmethod') 2357 # The 2 here is because we need both function and argument names. 2358 if isinstance(self.declarator, CFuncDeclaratorNode): 2359 name_declarator, type = self.declarator.analyse( 2360 base_type, env, nonempty=2 * (self.body is not None), 2361 directive_locals=self.directive_locals, visibility=self.visibility) 2362 else: 2363 name_declarator, type = self.declarator.analyse( 2364 base_type, env, nonempty=2 * (self.body is not None), visibility=self.visibility) 2365 if not type.is_cfunction: 2366 error(self.pos, "Suite attached to non-function declaration") 2367 # Remember the actual type according to the function header 2368 # written here, because the type in the symbol table entry 2369 # may be different if we're overriding a C method inherited 2370 # from the base type of an extension type. 2371 self.type = type 2372 type.is_overridable = self.overridable 2373 declarator = self.declarator 2374 while not hasattr(declarator, 'args'): 2375 declarator = declarator.base 2376 2377 self.cfunc_declarator = declarator 2378 self.args = declarator.args 2379 2380 opt_arg_count = self.cfunc_declarator.optional_arg_count 2381 if (self.visibility == 'public' or self.api) and opt_arg_count: 2382 error(self.cfunc_declarator.pos, 2383 "Function with optional arguments may not be declared public or api") 2384 2385 if type.exception_check == '+' and self.visibility != 'extern': 2386 warning(self.cfunc_declarator.pos, 2387 "Only extern functions can throw C++ exceptions.") 2388 2389 for formal_arg, type_arg in zip(self.args, type.args): 2390 self.align_argument_type(env, type_arg) 2391 formal_arg.type = type_arg.type 2392 formal_arg.name = type_arg.name 2393 formal_arg.cname = type_arg.cname 2394 2395 self._validate_type_visibility(type_arg.type, type_arg.pos, env) 2396 2397 if type_arg.type.is_fused: 2398 self.has_fused_arguments = True 2399 2400 if type_arg.type.is_buffer and 'inline' in self.modifiers: 2401 warning(formal_arg.pos, "Buffer unpacking not optimized away.", 1) 2402 2403 if type_arg.type.is_buffer or type_arg.type.is_pythran_expr: 2404 if self.type.nogil: 2405 error(formal_arg.pos, 2406 "Buffer may not be acquired without the GIL. Consider using memoryview slices instead.") 2407 elif 'inline' in self.modifiers: 2408 warning(formal_arg.pos, "Buffer unpacking not optimized away.", 1) 2409 2410 self._validate_type_visibility(type.return_type, self.pos, env) 2411 2412 name = name_declarator.name 2413 cname = name_declarator.cname 2414 2415 type.is_const_method = self.is_const_method 2416 type.is_static_method = self.is_static_method 2417 self.entry = env.declare_cfunction( 2418 name, type, self.pos, 2419 cname=cname, visibility=self.visibility, api=self.api, 2420 defining=self.body is not None, modifiers=self.modifiers, 2421 overridable=self.overridable) 2422 self.entry.inline_func_in_pxd = self.inline_in_pxd 2423 self.return_type = type.return_type 2424 if self.return_type.is_array and self.visibility != 'extern': 2425 error(self.pos, "Function cannot return an array") 2426 if self.return_type.is_cpp_class: 2427 self.return_type.check_nullary_constructor(self.pos, "used as a return value") 2428 2429 if self.overridable and not env.is_module_scope and not self.is_static_method: 2430 if len(self.args) < 1 or not self.args[0].type.is_pyobject: 2431 # An error will be produced in the cdef function 2432 self.overridable = False 2433 2434 self.declare_cpdef_wrapper(env) 2435 self.create_local_scope(env) 2436 2437 def declare_cpdef_wrapper(self, env): 2438 if self.overridable: 2439 if self.is_static_method: 2440 # TODO(robertwb): Finish this up, perhaps via more function refactoring. 2441 error(self.pos, "static cpdef methods not yet supported") 2442 name = self.entry.name 2443 py_func_body = self.call_self_node(is_module_scope=env.is_module_scope) 2444 if self.is_static_method: 2445 from .ExprNodes import NameNode 2446 decorators = [DecoratorNode(self.pos, decorator=NameNode(self.pos, name='staticmethod'))] 2447 decorators[0].decorator.analyse_types(env) 2448 else: 2449 decorators = [] 2450 self.py_func = DefNode(pos=self.pos, 2451 name=self.entry.name, 2452 args=self.args, 2453 star_arg=None, 2454 starstar_arg=None, 2455 doc=self.doc, 2456 body=py_func_body, 2457 decorators=decorators, 2458 is_wrapper=1) 2459 self.py_func.is_module_scope = env.is_module_scope 2460 self.py_func.analyse_declarations(env) 2461 self.py_func.entry.is_overridable = True 2462 self.py_func_stat = StatListNode(self.pos, stats=[self.py_func]) 2463 self.py_func.type = PyrexTypes.py_object_type 2464 self.entry.as_variable = self.py_func.entry 2465 self.entry.used = self.entry.as_variable.used = True 2466 # Reset scope entry the above cfunction 2467 env.entries[name] = self.entry 2468 if (not self.entry.is_final_cmethod and 2469 (not env.is_module_scope or Options.lookup_module_cpdef)): 2470 self.override = OverrideCheckNode(self.pos, py_func=self.py_func) 2471 self.body = StatListNode(self.pos, stats=[self.override, self.body]) 2472 2473 def _validate_type_visibility(self, type, pos, env): 2474 """ 2475 Ensure that types used in cdef functions are public or api, or 2476 defined in a C header. 2477 """ 2478 public_or_api = (self.visibility == 'public' or self.api) 2479 entry = getattr(type, 'entry', None) 2480 if public_or_api and entry and env.is_module_scope: 2481 if not (entry.visibility in ('public', 'extern') or 2482 entry.api or entry.in_cinclude): 2483 error(pos, "Function declared public or api may not have private types") 2484 2485 def call_self_node(self, omit_optional_args=0, is_module_scope=0): 2486 from . import ExprNodes 2487 args = self.type.args 2488 if omit_optional_args: 2489 args = args[:len(args) - self.type.optional_arg_count] 2490 arg_names = [arg.name for arg in args] 2491 if is_module_scope: 2492 cfunc = ExprNodes.NameNode(self.pos, name=self.entry.name) 2493 call_arg_names = arg_names 2494 skip_dispatch = Options.lookup_module_cpdef 2495 elif self.type.is_static_method: 2496 class_entry = self.entry.scope.parent_type.entry 2497 class_node = ExprNodes.NameNode(self.pos, name=class_entry.name) 2498 class_node.entry = class_entry 2499 cfunc = ExprNodes.AttributeNode(self.pos, obj=class_node, attribute=self.entry.name) 2500 # Calling static c(p)def methods on an instance disallowed. 2501 # TODO(robertwb): Support by passing self to check for override? 2502 skip_dispatch = True 2503 else: 2504 type_entry = self.type.args[0].type.entry 2505 type_arg = ExprNodes.NameNode(self.pos, name=type_entry.name) 2506 type_arg.entry = type_entry 2507 cfunc = ExprNodes.AttributeNode(self.pos, obj=type_arg, attribute=self.entry.name) 2508 skip_dispatch = not is_module_scope or Options.lookup_module_cpdef 2509 c_call = ExprNodes.SimpleCallNode( 2510 self.pos, 2511 function=cfunc, 2512 args=[ExprNodes.NameNode(self.pos, name=n) for n in arg_names], 2513 wrapper_call=skip_dispatch) 2514 return ReturnStatNode(pos=self.pos, return_type=PyrexTypes.py_object_type, value=c_call) 2515 2516 def declare_arguments(self, env): 2517 for arg in self.type.args: 2518 if not arg.name: 2519 error(arg.pos, "Missing argument name") 2520 self.declare_argument(env, arg) 2521 2522 def need_gil_acquisition(self, lenv): 2523 return self.type.with_gil 2524 2525 def nogil_check(self, env): 2526 type = self.type 2527 with_gil = type.with_gil 2528 if type.nogil and not with_gil: 2529 if type.return_type.is_pyobject: 2530 error(self.pos, 2531 "Function with Python return type cannot be declared nogil") 2532 for entry in self.local_scope.var_entries: 2533 if entry.type.is_pyobject and not entry.in_with_gil_block: 2534 error(self.pos, "Function declared nogil has Python locals or temporaries") 2535 2536 def analyse_expressions(self, env): 2537 self.local_scope.directives = env.directives 2538 if self.py_func_stat is not None: 2539 # this will also analyse the default values and the function name assignment 2540 self.py_func_stat = self.py_func_stat.analyse_expressions(env) 2541 elif self.py_func is not None: 2542 # this will also analyse the default values 2543 self.py_func = self.py_func.analyse_expressions(env) 2544 else: 2545 self.analyse_default_values(env) 2546 self.analyse_annotations(env) 2547 self.acquire_gil = self.need_gil_acquisition(self.local_scope) 2548 return self 2549 2550 def needs_assignment_synthesis(self, env, code=None): 2551 return False 2552 2553 def generate_function_header(self, code, with_pymethdef, with_opt_args=1, with_dispatch=1, cname=None): 2554 scope = self.local_scope 2555 arg_decls = [] 2556 type = self.type 2557 for arg in type.args[:len(type.args)-type.optional_arg_count]: 2558 arg_decl = arg.declaration_code() 2559 entry = scope.lookup(arg.name) 2560 if not entry.cf_used: 2561 arg_decl = 'CYTHON_UNUSED %s' % arg_decl 2562 arg_decls.append(arg_decl) 2563 if with_dispatch and self.overridable: 2564 dispatch_arg = PyrexTypes.c_int_type.declaration_code( 2565 Naming.skip_dispatch_cname) 2566 if self.override: 2567 arg_decls.append(dispatch_arg) 2568 else: 2569 arg_decls.append('CYTHON_UNUSED %s' % dispatch_arg) 2570 if type.optional_arg_count and with_opt_args: 2571 arg_decls.append(type.op_arg_struct.declaration_code(Naming.optional_args_cname)) 2572 if type.has_varargs: 2573 arg_decls.append("...") 2574 if not arg_decls: 2575 arg_decls = ["void"] 2576 if cname is None: 2577 cname = self.entry.func_cname 2578 entity = type.function_header_code(cname, ', '.join(arg_decls)) 2579 if self.entry.visibility == 'private' and '::' not in cname: 2580 storage_class = "static " 2581 else: 2582 storage_class = "" 2583 dll_linkage = None 2584 modifiers = code.build_function_modifiers(self.entry.func_modifiers) 2585 2586 header = self.return_type.declaration_code(entity, dll_linkage=dll_linkage) 2587 #print (storage_class, modifiers, header) 2588 needs_proto = self.is_c_class_method 2589 if self.template_declaration: 2590 if needs_proto: 2591 code.globalstate.parts['module_declarations'].putln(self.template_declaration) 2592 code.putln(self.template_declaration) 2593 if needs_proto: 2594 code.globalstate.parts['module_declarations'].putln( 2595 "%s%s%s; /* proto*/" % (storage_class, modifiers, header)) 2596 code.putln("%s%s%s {" % (storage_class, modifiers, header)) 2597 2598 def generate_argument_declarations(self, env, code): 2599 scope = self.local_scope 2600 for arg in self.args: 2601 if arg.default: 2602 entry = scope.lookup(arg.name) 2603 if self.override or entry.cf_used: 2604 result = arg.calculate_default_value_code(code) 2605 code.putln('%s = %s;' % ( 2606 arg.type.declaration_code(arg.cname), result)) 2607 2608 def generate_keyword_list(self, code): 2609 pass 2610 2611 def generate_argument_parsing_code(self, env, code): 2612 i = 0 2613 used = 0 2614 scope = self.local_scope 2615 if self.type.optional_arg_count: 2616 code.putln('if (%s) {' % Naming.optional_args_cname) 2617 for arg in self.args: 2618 if arg.default: 2619 entry = scope.lookup(arg.name) 2620 if self.override or entry.cf_used: 2621 code.putln('if (%s->%sn > %s) {' % 2622 (Naming.optional_args_cname, 2623 Naming.pyrex_prefix, i)) 2624 declarator = arg.declarator 2625 while not hasattr(declarator, 'name'): 2626 declarator = declarator.base 2627 code.putln('%s = %s->%s;' % 2628 (arg.cname, Naming.optional_args_cname, 2629 self.type.opt_arg_cname(declarator.name))) 2630 used += 1 2631 i += 1 2632 for _ in range(used): 2633 code.putln('}') 2634 code.putln('}') 2635 2636 # Move arguments into closure if required 2637 def put_into_closure(entry): 2638 if entry.in_closure and not arg.default: 2639 code.putln('%s = %s;' % (entry.cname, entry.original_cname)) 2640 code.put_var_incref(entry) 2641 code.put_var_giveref(entry) 2642 for arg in self.args: 2643 put_into_closure(scope.lookup_here(arg.name)) 2644 2645 2646 def generate_argument_conversion_code(self, code): 2647 pass 2648 2649 def generate_argument_type_tests(self, code): 2650 # Generate type tests for args whose type in a parent 2651 # class is a supertype of the declared type. 2652 for arg in self.type.args: 2653 if arg.needs_type_test: 2654 self.generate_arg_type_test(arg, code) 2655 elif arg.type.is_pyobject and not arg.accept_none: 2656 self.generate_arg_none_check(arg, code) 2657 2658 def generate_execution_code(self, code): 2659 if code.globalstate.directives['linetrace']: 2660 code.mark_pos(self.pos) 2661 code.putln("") # generate line tracing code 2662 super(CFuncDefNode, self).generate_execution_code(code) 2663 if self.py_func_stat: 2664 self.py_func_stat.generate_execution_code(code) 2665 2666 def error_value(self): 2667 if self.return_type.is_pyobject: 2668 return "0" 2669 else: 2670 #return None 2671 return self.entry.type.exception_value 2672 2673 def caller_will_check_exceptions(self): 2674 return self.entry.type.exception_check 2675 2676 def generate_wrapper_functions(self, code): 2677 # If the C signature of a function has changed, we need to generate 2678 # wrappers to put in the slots here. 2679 k = 0 2680 entry = self.entry 2681 func_type = entry.type 2682 while entry.prev_entry is not None: 2683 k += 1 2684 entry = entry.prev_entry 2685 entry.func_cname = "%s%swrap_%s" % (self.entry.func_cname, Naming.pyrex_prefix, k) 2686 code.putln() 2687 self.generate_function_header( 2688 code, 0, 2689 with_dispatch=entry.type.is_overridable, 2690 with_opt_args=entry.type.optional_arg_count, 2691 cname=entry.func_cname) 2692 if not self.return_type.is_void: 2693 code.put('return ') 2694 args = self.type.args 2695 arglist = [arg.cname for arg in args[:len(args)-self.type.optional_arg_count]] 2696 if entry.type.is_overridable: 2697 arglist.append(Naming.skip_dispatch_cname) 2698 elif func_type.is_overridable: 2699 arglist.append('0') 2700 if entry.type.optional_arg_count: 2701 arglist.append(Naming.optional_args_cname) 2702 elif func_type.optional_arg_count: 2703 arglist.append('NULL') 2704 code.putln('%s(%s);' % (self.entry.func_cname, ', '.join(arglist))) 2705 code.putln('}') 2706 2707 2708class PyArgDeclNode(Node): 2709 # Argument which must be a Python object (used 2710 # for * and ** arguments). 2711 # 2712 # name string 2713 # entry Symtab.Entry 2714 # annotation ExprNode or None Py3 argument annotation 2715 child_attrs = [] 2716 is_self_arg = False 2717 is_type_arg = False 2718 2719 def generate_function_definitions(self, env, code): 2720 self.entry.generate_function_definitions(env, code) 2721 2722 2723class DecoratorNode(Node): 2724 # A decorator 2725 # 2726 # decorator NameNode or CallNode or AttributeNode 2727 child_attrs = ['decorator'] 2728 2729 2730class DefNode(FuncDefNode): 2731 # A Python function definition. 2732 # 2733 # name string the Python name of the function 2734 # lambda_name string the internal name of a lambda 'function' 2735 # decorators [DecoratorNode] list of decorators 2736 # args [CArgDeclNode] formal arguments 2737 # doc EncodedString or None 2738 # body StatListNode 2739 # return_type_annotation 2740 # ExprNode or None the Py3 return type annotation 2741 # 2742 # The following subnode is constructed internally 2743 # when the def statement is inside a Python class definition. 2744 # 2745 # fused_py_func DefNode The original fused cpdef DefNode 2746 # (in case this is a specialization) 2747 # specialized_cpdefs [DefNode] list of specialized cpdef DefNodes 2748 # py_cfunc_node PyCFunctionNode/InnerFunctionNode The PyCFunction to create and assign 2749 # 2750 # decorator_indirection IndirectionNode Used to remove __Pyx_Method_ClassMethod for fused functions 2751 2752 child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators", "return_type_annotation"] 2753 outer_attrs = ["decorators", "return_type_annotation"] 2754 2755 is_staticmethod = False 2756 is_classmethod = False 2757 2758 lambda_name = None 2759 reqd_kw_flags_cname = "0" 2760 is_wrapper = 0 2761 no_assignment_synthesis = 0 2762 decorators = None 2763 return_type_annotation = None 2764 entry = None 2765 acquire_gil = 0 2766 self_in_stararg = 0 2767 py_cfunc_node = None 2768 requires_classobj = False 2769 defaults_struct = None # Dynamic kwrds structure name 2770 doc = None 2771 2772 fused_py_func = False 2773 specialized_cpdefs = None 2774 py_wrapper = None 2775 py_wrapper_required = True 2776 func_cname = None 2777 2778 defaults_getter = None 2779 2780 def __init__(self, pos, **kwds): 2781 FuncDefNode.__init__(self, pos, **kwds) 2782 k = rk = r = 0 2783 for arg in self.args: 2784 if arg.kw_only: 2785 k += 1 2786 if not arg.default: 2787 rk += 1 2788 if not arg.default: 2789 r += 1 2790 self.num_kwonly_args = k 2791 self.num_required_kw_args = rk 2792 self.num_required_args = r 2793 2794 def as_cfunction(self, cfunc=None, scope=None, overridable=True, returns=None, except_val=None, modifiers=None, 2795 nogil=False, with_gil=False): 2796 if self.star_arg: 2797 error(self.star_arg.pos, "cdef function cannot have star argument") 2798 if self.starstar_arg: 2799 error(self.starstar_arg.pos, "cdef function cannot have starstar argument") 2800 exception_value, exception_check = except_val or (None, False) 2801 2802 if cfunc is None: 2803 cfunc_args = [] 2804 for formal_arg in self.args: 2805 name_declarator, type = formal_arg.analyse(scope, nonempty=1) 2806 cfunc_args.append(PyrexTypes.CFuncTypeArg(name=name_declarator.name, 2807 cname=None, 2808 annotation=formal_arg.annotation, 2809 type=py_object_type, 2810 pos=formal_arg.pos)) 2811 cfunc_type = PyrexTypes.CFuncType(return_type=py_object_type, 2812 args=cfunc_args, 2813 has_varargs=False, 2814 exception_value=None, 2815 exception_check=exception_check, 2816 nogil=nogil, 2817 with_gil=with_gil, 2818 is_overridable=overridable) 2819 cfunc = CVarDefNode(self.pos, type=cfunc_type) 2820 else: 2821 if scope is None: 2822 scope = cfunc.scope 2823 cfunc_type = cfunc.type 2824 if len(self.args) != len(cfunc_type.args) or cfunc_type.has_varargs: 2825 error(self.pos, "wrong number of arguments") 2826 error(cfunc.pos, "previous declaration here") 2827 for i, (formal_arg, type_arg) in enumerate(zip(self.args, cfunc_type.args)): 2828 name_declarator, type = formal_arg.analyse(scope, nonempty=1, 2829 is_self_arg=(i == 0 and scope.is_c_class_scope)) 2830 if type is None or type is PyrexTypes.py_object_type: 2831 formal_arg.type = type_arg.type 2832 formal_arg.name_declarator = name_declarator 2833 2834 if exception_value is None and cfunc_type.exception_value is not None: 2835 from .ExprNodes import ConstNode 2836 exception_value = ConstNode( 2837 self.pos, value=cfunc_type.exception_value, type=cfunc_type.return_type) 2838 declarator = CFuncDeclaratorNode(self.pos, 2839 base=CNameDeclaratorNode(self.pos, name=self.name, cname=None), 2840 args=self.args, 2841 has_varargs=False, 2842 exception_check=cfunc_type.exception_check, 2843 exception_value=exception_value, 2844 with_gil=cfunc_type.with_gil, 2845 nogil=cfunc_type.nogil) 2846 return CFuncDefNode(self.pos, 2847 modifiers=modifiers or [], 2848 base_type=CAnalysedBaseTypeNode(self.pos, type=cfunc_type.return_type), 2849 declarator=declarator, 2850 body=self.body, 2851 doc=self.doc, 2852 overridable=cfunc_type.is_overridable, 2853 type=cfunc_type, 2854 with_gil=cfunc_type.with_gil, 2855 nogil=cfunc_type.nogil, 2856 visibility='private', 2857 api=False, 2858 directive_locals=getattr(cfunc, 'directive_locals', {}), 2859 directive_returns=returns) 2860 2861 def is_cdef_func_compatible(self): 2862 """Determines if the function's signature is compatible with a 2863 cdef function. This can be used before calling 2864 .as_cfunction() to see if that will be successful. 2865 """ 2866 if self.needs_closure: 2867 return False 2868 if self.star_arg or self.starstar_arg: 2869 return False 2870 return True 2871 2872 def analyse_declarations(self, env): 2873 if self.decorators: 2874 for decorator in self.decorators: 2875 func = decorator.decorator 2876 if func.is_name: 2877 self.is_classmethod |= func.name == 'classmethod' 2878 self.is_staticmethod |= func.name == 'staticmethod' 2879 2880 if self.is_classmethod and env.lookup_here('classmethod'): 2881 # classmethod() was overridden - not much we can do here ... 2882 self.is_classmethod = False 2883 if self.is_staticmethod and env.lookup_here('staticmethod'): 2884 # staticmethod() was overridden - not much we can do here ... 2885 self.is_staticmethod = False 2886 2887 if self.name == '__new__' and env.is_py_class_scope: 2888 self.is_staticmethod = 1 2889 2890 self.analyse_argument_types(env) 2891 if self.name == '<lambda>': 2892 self.declare_lambda_function(env) 2893 else: 2894 self.declare_pyfunction(env) 2895 2896 self.analyse_signature(env) 2897 self.return_type = self.entry.signature.return_type() 2898 # if a signature annotation provides a more specific return object type, use it 2899 if self.return_type is py_object_type and self.return_type_annotation: 2900 if env.directives['annotation_typing'] and not self.entry.is_special: 2901 _, return_type = analyse_type_annotation(self.return_type_annotation, env) 2902 if return_type and return_type.is_pyobject: 2903 self.return_type = return_type 2904 2905 self.create_local_scope(env) 2906 2907 self.py_wrapper = DefNodeWrapper( 2908 self.pos, 2909 target=self, 2910 name=self.entry.name, 2911 args=self.args, 2912 star_arg=self.star_arg, 2913 starstar_arg=self.starstar_arg, 2914 return_type=self.return_type) 2915 self.py_wrapper.analyse_declarations(env) 2916 2917 def analyse_argument_types(self, env): 2918 self.directive_locals = env.directives.get('locals', {}) 2919 allow_none_for_extension_args = env.directives['allow_none_for_extension_args'] 2920 2921 f2s = env.fused_to_specific 2922 env.fused_to_specific = None 2923 2924 for arg in self.args: 2925 if hasattr(arg, 'name'): 2926 name_declarator = None 2927 else: 2928 base_type = arg.base_type.analyse(env) 2929 # If we hare in pythran mode and we got a buffer supported by 2930 # Pythran, we change this node to a fused type 2931 if has_np_pythran(env) and base_type.is_pythran_expr: 2932 base_type = PyrexTypes.FusedType([ 2933 base_type, 2934 #PyrexTypes.PythranExpr(pythran_type(self.type, "numpy_texpr")), 2935 base_type.org_buffer]) 2936 name_declarator, type = \ 2937 arg.declarator.analyse(base_type, env) 2938 arg.name = name_declarator.name 2939 arg.type = type 2940 2941 if type.is_fused: 2942 self.has_fused_arguments = True 2943 2944 self.align_argument_type(env, arg) 2945 if name_declarator and name_declarator.cname: 2946 error(self.pos, "Python function argument cannot have C name specification") 2947 arg.type = arg.type.as_argument_type() 2948 arg.hdr_type = None 2949 arg.needs_conversion = 0 2950 arg.needs_type_test = 0 2951 arg.is_generic = 1 2952 if arg.type.is_pyobject or arg.type.is_buffer or arg.type.is_memoryviewslice: 2953 if arg.or_none: 2954 arg.accept_none = True 2955 elif arg.not_none: 2956 arg.accept_none = False 2957 elif (arg.type.is_extension_type or arg.type.is_builtin_type 2958 or arg.type.is_buffer or arg.type.is_memoryviewslice): 2959 if arg.default and arg.default.constant_result is None: 2960 # special case: def func(MyType obj = None) 2961 arg.accept_none = True 2962 else: 2963 # default depends on compiler directive 2964 arg.accept_none = allow_none_for_extension_args 2965 else: 2966 # probably just a plain 'object' 2967 arg.accept_none = True 2968 else: 2969 arg.accept_none = True # won't be used, but must be there 2970 if arg.not_none: 2971 error(arg.pos, "Only Python type arguments can have 'not None'") 2972 if arg.or_none: 2973 error(arg.pos, "Only Python type arguments can have 'or None'") 2974 env.fused_to_specific = f2s 2975 2976 if has_np_pythran(env): 2977 self.np_args_idx = [i for i,a in enumerate(self.args) if a.type.is_numpy_buffer] 2978 else: 2979 self.np_args_idx = [] 2980 2981 def analyse_signature(self, env): 2982 if self.entry.is_special: 2983 if self.decorators: 2984 error(self.pos, "special functions of cdef classes cannot have decorators") 2985 self.entry.trivial_signature = len(self.args) == 1 and not (self.star_arg or self.starstar_arg) 2986 elif not env.directives['always_allow_keywords'] and not (self.star_arg or self.starstar_arg): 2987 # Use the simpler calling signature for zero- and one-argument functions. 2988 if self.entry.signature is TypeSlots.pyfunction_signature: 2989 if len(self.args) == 0: 2990 self.entry.signature = TypeSlots.pyfunction_noargs 2991 elif len(self.args) == 1: 2992 if self.args[0].default is None and not self.args[0].kw_only: 2993 self.entry.signature = TypeSlots.pyfunction_onearg 2994 elif self.entry.signature is TypeSlots.pymethod_signature: 2995 if len(self.args) == 1: 2996 self.entry.signature = TypeSlots.unaryfunc 2997 elif len(self.args) == 2: 2998 if self.args[1].default is None and not self.args[1].kw_only: 2999 self.entry.signature = TypeSlots.ibinaryfunc 3000 3001 sig = self.entry.signature 3002 nfixed = sig.num_fixed_args() 3003 if (sig is TypeSlots.pymethod_signature and nfixed == 1 3004 and len(self.args) == 0 and self.star_arg): 3005 # this is the only case where a diverging number of 3006 # arguments is not an error - when we have no explicit 3007 # 'self' parameter as in method(*args) 3008 sig = self.entry.signature = TypeSlots.pyfunction_signature # self is not 'really' used 3009 self.self_in_stararg = 1 3010 nfixed = 0 3011 3012 if self.is_staticmethod and env.is_c_class_scope: 3013 nfixed = 0 3014 self.self_in_stararg = True # FIXME: why for staticmethods? 3015 3016 self.entry.signature = sig = copy.copy(sig) 3017 sig.fixed_arg_format = "*" 3018 sig.is_staticmethod = True 3019 sig.has_generic_args = True 3020 3021 if ((self.is_classmethod or self.is_staticmethod) and 3022 self.has_fused_arguments and env.is_c_class_scope): 3023 del self.decorator_indirection.stats[:] 3024 3025 for i in range(min(nfixed, len(self.args))): 3026 arg = self.args[i] 3027 arg.is_generic = 0 3028 if sig.is_self_arg(i) and not self.is_staticmethod: 3029 if self.is_classmethod: 3030 arg.is_type_arg = 1 3031 arg.hdr_type = arg.type = Builtin.type_type 3032 else: 3033 arg.is_self_arg = 1 3034 arg.hdr_type = arg.type = env.parent_type 3035 arg.needs_conversion = 0 3036 else: 3037 arg.hdr_type = sig.fixed_arg_type(i) 3038 if not arg.type.same_as(arg.hdr_type): 3039 if arg.hdr_type.is_pyobject and arg.type.is_pyobject: 3040 arg.needs_type_test = 1 3041 else: 3042 arg.needs_conversion = 1 3043 if arg.needs_conversion: 3044 arg.hdr_cname = Naming.arg_prefix + arg.name 3045 else: 3046 arg.hdr_cname = Naming.var_prefix + arg.name 3047 3048 if nfixed > len(self.args): 3049 self.bad_signature() 3050 return 3051 elif nfixed < len(self.args): 3052 if not sig.has_generic_args: 3053 self.bad_signature() 3054 for arg in self.args: 3055 if arg.is_generic and (arg.type.is_extension_type or arg.type.is_builtin_type): 3056 arg.needs_type_test = 1 3057 3058 def bad_signature(self): 3059 sig = self.entry.signature 3060 expected_str = "%d" % sig.num_fixed_args() 3061 if sig.has_generic_args: 3062 expected_str += " or more" 3063 name = self.name 3064 if name.startswith("__") and name.endswith("__"): 3065 desc = "Special method" 3066 else: 3067 desc = "Method" 3068 error(self.pos, "%s %s has wrong number of arguments (%d declared, %s expected)" % ( 3069 desc, self.name, len(self.args), expected_str)) 3070 3071 def declare_pyfunction(self, env): 3072 #print "DefNode.declare_pyfunction:", self.name, "in", env ### 3073 name = self.name 3074 entry = env.lookup_here(name) 3075 if entry: 3076 if entry.is_final_cmethod and not env.parent_type.is_final_type: 3077 error(self.pos, "Only final types can have final Python (def/cpdef) methods") 3078 if entry.type.is_cfunction and not entry.is_builtin_cmethod and not self.is_wrapper: 3079 warning(self.pos, "Overriding cdef method with def method.", 5) 3080 entry = env.declare_pyfunction(name, self.pos, allow_redefine=not self.is_wrapper) 3081 self.entry = entry 3082 prefix = env.next_id(env.scope_prefix) 3083 self.entry.pyfunc_cname = Naming.pyfunc_prefix + prefix + name 3084 if Options.docstrings: 3085 entry.doc = embed_position(self.pos, self.doc) 3086 entry.doc_cname = Naming.funcdoc_prefix + prefix + name 3087 if entry.is_special: 3088 if entry.name in TypeSlots.invisible or not entry.doc or ( 3089 entry.name in '__getattr__' and env.directives['fast_getattr']): 3090 entry.wrapperbase_cname = None 3091 else: 3092 entry.wrapperbase_cname = Naming.wrapperbase_prefix + prefix + name 3093 else: 3094 entry.doc = None 3095 3096 def declare_lambda_function(self, env): 3097 entry = env.declare_lambda_function(self.lambda_name, self.pos) 3098 entry.doc = None 3099 self.entry = entry 3100 self.entry.pyfunc_cname = entry.cname 3101 3102 def declare_arguments(self, env): 3103 for arg in self.args: 3104 if not arg.name: 3105 error(arg.pos, "Missing argument name") 3106 if arg.needs_conversion: 3107 arg.entry = env.declare_var(arg.name, arg.type, arg.pos) 3108 if arg.type.is_pyobject: 3109 arg.entry.init = "0" 3110 else: 3111 arg.entry = self.declare_argument(env, arg) 3112 arg.entry.is_arg = 1 3113 arg.entry.used = 1 3114 arg.entry.is_self_arg = arg.is_self_arg 3115 self.declare_python_arg(env, self.star_arg) 3116 self.declare_python_arg(env, self.starstar_arg) 3117 3118 def declare_python_arg(self, env, arg): 3119 if arg: 3120 if env.directives['infer_types'] != False: 3121 type = PyrexTypes.unspecified_type 3122 else: 3123 type = py_object_type 3124 entry = env.declare_var(arg.name, type, arg.pos) 3125 entry.is_arg = 1 3126 entry.used = 1 3127 entry.init = "0" 3128 entry.xdecref_cleanup = 1 3129 arg.entry = entry 3130 3131 def analyse_expressions(self, env): 3132 self.local_scope.directives = env.directives 3133 self.analyse_default_values(env) 3134 self.analyse_annotations(env) 3135 if self.return_type_annotation: 3136 self.return_type_annotation = self.analyse_annotation(env, self.return_type_annotation) 3137 3138 if not self.needs_assignment_synthesis(env) and self.decorators: 3139 for decorator in self.decorators[::-1]: 3140 decorator.decorator = decorator.decorator.analyse_expressions(env) 3141 3142 self.py_wrapper.prepare_argument_coercion(env) 3143 return self 3144 3145 def needs_assignment_synthesis(self, env, code=None): 3146 if self.is_staticmethod: 3147 return True 3148 if self.specialized_cpdefs or self.entry.is_fused_specialized: 3149 return False 3150 if self.no_assignment_synthesis: 3151 return False 3152 if self.entry.is_special: 3153 return False 3154 if self.entry.is_anonymous: 3155 return True 3156 if env.is_module_scope or env.is_c_class_scope: 3157 if code is None: 3158 return self.local_scope.directives['binding'] 3159 else: 3160 return code.globalstate.directives['binding'] 3161 return env.is_py_class_scope or env.is_closure_scope 3162 3163 def error_value(self): 3164 return self.entry.signature.error_value 3165 3166 def caller_will_check_exceptions(self): 3167 return self.entry.signature.exception_check 3168 3169 def generate_function_definitions(self, env, code): 3170 if self.defaults_getter: 3171 # defaults getter must never live in class scopes, it's always a module function 3172 self.defaults_getter.generate_function_definitions(env.global_scope(), code) 3173 3174 # Before closure cnames are mangled 3175 if self.py_wrapper_required: 3176 # func_cname might be modified by @cname 3177 self.py_wrapper.func_cname = self.entry.func_cname 3178 self.py_wrapper.generate_function_definitions(env, code) 3179 FuncDefNode.generate_function_definitions(self, env, code) 3180 3181 def generate_function_header(self, code, with_pymethdef, proto_only=0): 3182 if proto_only: 3183 if self.py_wrapper_required: 3184 self.py_wrapper.generate_function_header( 3185 code, with_pymethdef, True) 3186 return 3187 arg_code_list = [] 3188 if self.entry.signature.has_dummy_arg: 3189 self_arg = 'PyObject *%s' % Naming.self_cname 3190 if not self.needs_outer_scope: 3191 self_arg = 'CYTHON_UNUSED ' + self_arg 3192 arg_code_list.append(self_arg) 3193 3194 def arg_decl_code(arg): 3195 entry = arg.entry 3196 if entry.in_closure: 3197 cname = entry.original_cname 3198 else: 3199 cname = entry.cname 3200 decl = entry.type.declaration_code(cname) 3201 if not entry.cf_used: 3202 decl = 'CYTHON_UNUSED ' + decl 3203 return decl 3204 3205 for arg in self.args: 3206 arg_code_list.append(arg_decl_code(arg)) 3207 if self.star_arg: 3208 arg_code_list.append(arg_decl_code(self.star_arg)) 3209 if self.starstar_arg: 3210 arg_code_list.append(arg_decl_code(self.starstar_arg)) 3211 if arg_code_list: 3212 arg_code = ', '.join(arg_code_list) 3213 else: 3214 arg_code = 'void' # No arguments 3215 dc = self.return_type.declaration_code(self.entry.pyfunc_cname) 3216 3217 decls_code = code.globalstate['decls'] 3218 preprocessor_guard = self.get_preprocessor_guard() 3219 if preprocessor_guard: 3220 decls_code.putln(preprocessor_guard) 3221 decls_code.putln( 3222 "static %s(%s); /* proto */" % (dc, arg_code)) 3223 if preprocessor_guard: 3224 decls_code.putln("#endif") 3225 code.putln("static %s(%s) {" % (dc, arg_code)) 3226 3227 def generate_argument_declarations(self, env, code): 3228 pass 3229 3230 def generate_keyword_list(self, code): 3231 pass 3232 3233 def generate_argument_parsing_code(self, env, code): 3234 # Move arguments into closure if required 3235 def put_into_closure(entry): 3236 if entry.in_closure: 3237 code.putln('%s = %s;' % (entry.cname, entry.original_cname)) 3238 if entry.xdecref_cleanup: 3239 # mostly applies to the starstar arg - this can sometimes be NULL 3240 # so must be xincrefed instead 3241 code.put_var_xincref(entry) 3242 code.put_var_xgiveref(entry) 3243 else: 3244 code.put_var_incref(entry) 3245 code.put_var_giveref(entry) 3246 for arg in self.args: 3247 put_into_closure(arg.entry) 3248 for arg in self.star_arg, self.starstar_arg: 3249 if arg: 3250 put_into_closure(arg.entry) 3251 3252 def generate_argument_type_tests(self, code): 3253 pass 3254 3255 3256class DefNodeWrapper(FuncDefNode): 3257 # DefNode python wrapper code generator 3258 3259 defnode = None 3260 target = None # Target DefNode 3261 3262 def __init__(self, *args, **kwargs): 3263 FuncDefNode.__init__(self, *args, **kwargs) 3264 self.num_kwonly_args = self.target.num_kwonly_args 3265 self.num_required_kw_args = self.target.num_required_kw_args 3266 self.num_required_args = self.target.num_required_args 3267 self.self_in_stararg = self.target.self_in_stararg 3268 self.signature = None 3269 3270 def analyse_declarations(self, env): 3271 target_entry = self.target.entry 3272 name = self.name 3273 prefix = env.next_id(env.scope_prefix) 3274 target_entry.func_cname = Naming.pywrap_prefix + prefix + name 3275 target_entry.pymethdef_cname = Naming.pymethdef_prefix + prefix + name 3276 3277 self.signature = target_entry.signature 3278 3279 self.np_args_idx = self.target.np_args_idx 3280 3281 def prepare_argument_coercion(self, env): 3282 # This is only really required for Cython utility code at this time, 3283 # everything else can be done during code generation. But we expand 3284 # all utility code here, simply because we cannot easily distinguish 3285 # different code types. 3286 for arg in self.args: 3287 if not arg.type.is_pyobject: 3288 if not arg.type.create_from_py_utility_code(env): 3289 pass # will fail later 3290 elif arg.hdr_type and not arg.hdr_type.is_pyobject: 3291 if not arg.hdr_type.create_to_py_utility_code(env): 3292 pass # will fail later 3293 3294 if self.starstar_arg and not self.starstar_arg.entry.cf_used: 3295 # we will set the kwargs argument to NULL instead of a new dict 3296 # and must therefore correct the control flow state 3297 entry = self.starstar_arg.entry 3298 entry.xdecref_cleanup = 1 3299 for ass in entry.cf_assignments: 3300 if not ass.is_arg and ass.lhs.is_name: 3301 ass.lhs.cf_maybe_null = True 3302 3303 def signature_has_nongeneric_args(self): 3304 argcount = len(self.args) 3305 if argcount == 0 or ( 3306 argcount == 1 and (self.args[0].is_self_arg or 3307 self.args[0].is_type_arg)): 3308 return 0 3309 return 1 3310 3311 def signature_has_generic_args(self): 3312 return self.signature.has_generic_args 3313 3314 def generate_function_body(self, code): 3315 args = [] 3316 if self.signature.has_dummy_arg: 3317 args.append(Naming.self_cname) 3318 for arg in self.args: 3319 if arg.hdr_type and not (arg.type.is_memoryviewslice or 3320 arg.type.is_struct or 3321 arg.type.is_complex): 3322 args.append(arg.type.cast_code(arg.entry.cname)) 3323 else: 3324 args.append(arg.entry.cname) 3325 if self.star_arg: 3326 args.append(self.star_arg.entry.cname) 3327 if self.starstar_arg: 3328 args.append(self.starstar_arg.entry.cname) 3329 args = ', '.join(args) 3330 if not self.return_type.is_void: 3331 code.put('%s = ' % Naming.retval_cname) 3332 code.putln('%s(%s);' % ( 3333 self.target.entry.pyfunc_cname, args)) 3334 3335 def generate_function_definitions(self, env, code): 3336 lenv = self.target.local_scope 3337 # Generate C code for header and body of function 3338 code.mark_pos(self.pos) 3339 code.putln("") 3340 code.putln("/* Python wrapper */") 3341 preprocessor_guard = self.target.get_preprocessor_guard() 3342 if preprocessor_guard: 3343 code.putln(preprocessor_guard) 3344 3345 code.enter_cfunc_scope(lenv) 3346 code.return_from_error_cleanup_label = code.new_label() 3347 3348 with_pymethdef = (self.target.needs_assignment_synthesis(env, code) or 3349 self.target.pymethdef_required) 3350 self.generate_function_header(code, with_pymethdef) 3351 self.generate_argument_declarations(lenv, code) 3352 tempvardecl_code = code.insertion_point() 3353 3354 if self.return_type.is_pyobject: 3355 retval_init = ' = 0' 3356 else: 3357 retval_init = '' 3358 if not self.return_type.is_void: 3359 code.putln('%s%s;' % ( 3360 self.return_type.declaration_code(Naming.retval_cname), 3361 retval_init)) 3362 code.put_declare_refcount_context() 3363 code.put_setup_refcount_context('%s (wrapper)' % self.name) 3364 3365 self.generate_argument_parsing_code(lenv, code) 3366 self.generate_argument_type_tests(code) 3367 self.generate_function_body(code) 3368 3369 # ----- Go back and insert temp variable declarations 3370 tempvardecl_code.put_temp_declarations(code.funcstate) 3371 3372 code.mark_pos(self.pos) 3373 code.putln("") 3374 code.putln("/* function exit code */") 3375 3376 # ----- Error cleanup 3377 if code.error_label in code.labels_used: 3378 code.put_goto(code.return_label) 3379 code.put_label(code.error_label) 3380 for cname, type in code.funcstate.all_managed_temps(): 3381 code.put_xdecref(cname, type) 3382 err_val = self.error_value() 3383 if err_val is not None: 3384 code.putln("%s = %s;" % (Naming.retval_cname, err_val)) 3385 3386 # ----- Non-error return cleanup 3387 code.put_label(code.return_label) 3388 for entry in lenv.var_entries: 3389 if entry.is_arg and entry.type.is_pyobject: 3390 code.put_var_decref(entry) 3391 3392 code.put_finish_refcount_context() 3393 if not self.return_type.is_void: 3394 code.putln("return %s;" % Naming.retval_cname) 3395 code.putln('}') 3396 code.exit_cfunc_scope() 3397 if preprocessor_guard: 3398 code.putln("#endif /*!(%s)*/" % preprocessor_guard) 3399 3400 def generate_function_header(self, code, with_pymethdef, proto_only=0): 3401 arg_code_list = [] 3402 sig = self.signature 3403 3404 if sig.has_dummy_arg or self.self_in_stararg: 3405 arg_code = "PyObject *%s" % Naming.self_cname 3406 if not sig.has_dummy_arg: 3407 arg_code = 'CYTHON_UNUSED ' + arg_code 3408 arg_code_list.append(arg_code) 3409 3410 for arg in self.args: 3411 if not arg.is_generic: 3412 if arg.is_self_arg or arg.is_type_arg: 3413 arg_code_list.append("PyObject *%s" % arg.hdr_cname) 3414 else: 3415 arg_code_list.append( 3416 arg.hdr_type.declaration_code(arg.hdr_cname)) 3417 entry = self.target.entry 3418 if not entry.is_special and sig.method_flags() == [TypeSlots.method_noargs]: 3419 arg_code_list.append("CYTHON_UNUSED PyObject *unused") 3420 if entry.scope.is_c_class_scope and entry.name == "__ipow__": 3421 arg_code_list.append("CYTHON_UNUSED PyObject *unused") 3422 if sig.has_generic_args: 3423 arg_code_list.append( 3424 "PyObject *%s, PyObject *%s" % ( 3425 Naming.args_cname, Naming.kwds_cname)) 3426 arg_code = ", ".join(arg_code_list) 3427 3428 # Prevent warning: unused function '__pyx_pw_5numpy_7ndarray_1__getbuffer__' 3429 mf = "" 3430 if (entry.name in ("__getbuffer__", "__releasebuffer__") 3431 and entry.scope.is_c_class_scope): 3432 mf = "CYTHON_UNUSED " 3433 with_pymethdef = False 3434 3435 dc = self.return_type.declaration_code(entry.func_cname) 3436 header = "static %s%s(%s)" % (mf, dc, arg_code) 3437 code.putln("%s; /*proto*/" % header) 3438 3439 if proto_only: 3440 if self.target.fused_py_func: 3441 # If we are the specialized version of the cpdef, we still 3442 # want the prototype for the "fused cpdef", in case we're 3443 # checking to see if our method was overridden in Python 3444 self.target.fused_py_func.generate_function_header( 3445 code, with_pymethdef, proto_only=True) 3446 return 3447 3448 if (Options.docstrings and entry.doc and 3449 not self.target.fused_py_func and 3450 not entry.scope.is_property_scope and 3451 (not entry.is_special or entry.wrapperbase_cname)): 3452 # h_code = code.globalstate['h_code'] 3453 docstr = entry.doc 3454 3455 if docstr.is_unicode: 3456 docstr = docstr.as_utf8_string() 3457 3458 if not (entry.is_special and entry.name in ('__getbuffer__', '__releasebuffer__')): 3459 code.putln('static char %s[] = %s;' % ( 3460 entry.doc_cname, 3461 docstr.as_c_string_literal())) 3462 3463 if entry.is_special: 3464 code.putln('#if CYTHON_COMPILING_IN_CPYTHON') 3465 code.putln( 3466 "struct wrapperbase %s;" % entry.wrapperbase_cname) 3467 code.putln('#endif') 3468 3469 if with_pymethdef or self.target.fused_py_func: 3470 code.put( 3471 "static PyMethodDef %s = " % entry.pymethdef_cname) 3472 code.put_pymethoddef(self.target.entry, ";", allow_skip=False) 3473 code.putln("%s {" % header) 3474 3475 def generate_argument_declarations(self, env, code): 3476 for arg in self.args: 3477 if arg.is_generic: 3478 if arg.needs_conversion: 3479 code.putln("PyObject *%s = 0;" % arg.hdr_cname) 3480 else: 3481 code.put_var_declaration(arg.entry) 3482 for entry in env.var_entries: 3483 if entry.is_arg: 3484 code.put_var_declaration(entry) 3485 3486 def generate_argument_parsing_code(self, env, code): 3487 # Generate fast equivalent of PyArg_ParseTuple call for 3488 # generic arguments, if any, including args/kwargs 3489 old_error_label = code.new_error_label() 3490 our_error_label = code.error_label 3491 end_label = code.new_label("argument_unpacking_done") 3492 3493 has_kwonly_args = self.num_kwonly_args > 0 3494 has_star_or_kw_args = self.star_arg is not None \ 3495 or self.starstar_arg is not None or has_kwonly_args 3496 3497 for arg in self.args: 3498 if not arg.type.is_pyobject: 3499 if not arg.type.create_from_py_utility_code(env): 3500 pass # will fail later 3501 3502 if not self.signature_has_generic_args(): 3503 if has_star_or_kw_args: 3504 error(self.pos, "This method cannot have * or keyword arguments") 3505 self.generate_argument_conversion_code(code) 3506 3507 elif not self.signature_has_nongeneric_args(): 3508 # func(*args) or func(**kw) or func(*args, **kw) 3509 self.generate_stararg_copy_code(code) 3510 3511 else: 3512 self.generate_tuple_and_keyword_parsing_code(self.args, end_label, code) 3513 3514 code.error_label = old_error_label 3515 if code.label_used(our_error_label): 3516 if not code.label_used(end_label): 3517 code.put_goto(end_label) 3518 code.put_label(our_error_label) 3519 if has_star_or_kw_args: 3520 self.generate_arg_decref(self.star_arg, code) 3521 if self.starstar_arg: 3522 if self.starstar_arg.entry.xdecref_cleanup: 3523 code.put_var_xdecref_clear(self.starstar_arg.entry) 3524 else: 3525 code.put_var_decref_clear(self.starstar_arg.entry) 3526 code.put_add_traceback(self.target.entry.qualified_name) 3527 code.put_finish_refcount_context() 3528 code.putln("return %s;" % self.error_value()) 3529 if code.label_used(end_label): 3530 code.put_label(end_label) 3531 3532 def generate_arg_xdecref(self, arg, code): 3533 if arg: 3534 code.put_var_xdecref_clear(arg.entry) 3535 3536 def generate_arg_decref(self, arg, code): 3537 if arg: 3538 code.put_var_decref_clear(arg.entry) 3539 3540 def generate_stararg_copy_code(self, code): 3541 if not self.star_arg: 3542 code.globalstate.use_utility_code( 3543 UtilityCode.load_cached("RaiseArgTupleInvalid", "FunctionArguments.c")) 3544 code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > 0)) {" % 3545 Naming.args_cname) 3546 code.put('__Pyx_RaiseArgtupleInvalid("%s", 1, 0, 0, PyTuple_GET_SIZE(%s)); return %s;' % ( 3547 self.name, Naming.args_cname, self.error_value())) 3548 code.putln("}") 3549 3550 if self.starstar_arg: 3551 if self.star_arg or not self.starstar_arg.entry.cf_used: 3552 kwarg_check = "unlikely(%s)" % Naming.kwds_cname 3553 else: 3554 kwarg_check = "%s" % Naming.kwds_cname 3555 else: 3556 kwarg_check = "unlikely(%s) && unlikely(PyDict_Size(%s) > 0)" % ( 3557 Naming.kwds_cname, Naming.kwds_cname) 3558 code.globalstate.use_utility_code( 3559 UtilityCode.load_cached("KeywordStringCheck", "FunctionArguments.c")) 3560 code.putln( 3561 "if (%s && unlikely(!__Pyx_CheckKeywordStrings(%s, \"%s\", %d))) return %s;" % ( 3562 kwarg_check, Naming.kwds_cname, self.name, 3563 bool(self.starstar_arg), self.error_value())) 3564 3565 if self.starstar_arg and self.starstar_arg.entry.cf_used: 3566 if all(ref.node.allow_null for ref in self.starstar_arg.entry.cf_references): 3567 code.putln("if (%s) {" % kwarg_check) 3568 code.putln("%s = PyDict_Copy(%s); if (unlikely(!%s)) return %s;" % ( 3569 self.starstar_arg.entry.cname, 3570 Naming.kwds_cname, 3571 self.starstar_arg.entry.cname, 3572 self.error_value())) 3573 code.put_gotref(self.starstar_arg.entry.cname) 3574 code.putln("} else {") 3575 code.putln("%s = NULL;" % (self.starstar_arg.entry.cname,)) 3576 code.putln("}") 3577 self.starstar_arg.entry.xdecref_cleanup = 1 3578 else: 3579 code.put("%s = (%s) ? PyDict_Copy(%s) : PyDict_New(); " % ( 3580 self.starstar_arg.entry.cname, 3581 Naming.kwds_cname, 3582 Naming.kwds_cname)) 3583 code.putln("if (unlikely(!%s)) return %s;" % ( 3584 self.starstar_arg.entry.cname, self.error_value())) 3585 self.starstar_arg.entry.xdecref_cleanup = 0 3586 code.put_gotref(self.starstar_arg.entry.cname) 3587 3588 if self.self_in_stararg and not self.target.is_staticmethod: 3589 # need to create a new tuple with 'self' inserted as first item 3590 code.put("%s = PyTuple_New(PyTuple_GET_SIZE(%s)+1); if (unlikely(!%s)) " % ( 3591 self.star_arg.entry.cname, 3592 Naming.args_cname, 3593 self.star_arg.entry.cname)) 3594 if self.starstar_arg and self.starstar_arg.entry.cf_used: 3595 code.putln("{") 3596 code.put_xdecref_clear(self.starstar_arg.entry.cname, py_object_type) 3597 code.putln("return %s;" % self.error_value()) 3598 code.putln("}") 3599 else: 3600 code.putln("return %s;" % self.error_value()) 3601 code.put_gotref(self.star_arg.entry.cname) 3602 code.put_incref(Naming.self_cname, py_object_type) 3603 code.put_giveref(Naming.self_cname) 3604 code.putln("PyTuple_SET_ITEM(%s, 0, %s);" % ( 3605 self.star_arg.entry.cname, Naming.self_cname)) 3606 temp = code.funcstate.allocate_temp(PyrexTypes.c_py_ssize_t_type, manage_ref=False) 3607 code.putln("for (%s=0; %s < PyTuple_GET_SIZE(%s); %s++) {" % ( 3608 temp, temp, Naming.args_cname, temp)) 3609 code.putln("PyObject* item = PyTuple_GET_ITEM(%s, %s);" % ( 3610 Naming.args_cname, temp)) 3611 code.put_incref("item", py_object_type) 3612 code.put_giveref("item") 3613 code.putln("PyTuple_SET_ITEM(%s, %s+1, item);" % ( 3614 self.star_arg.entry.cname, temp)) 3615 code.putln("}") 3616 code.funcstate.release_temp(temp) 3617 self.star_arg.entry.xdecref_cleanup = 0 3618 elif self.star_arg: 3619 code.put_incref(Naming.args_cname, py_object_type) 3620 code.putln("%s = %s;" % ( 3621 self.star_arg.entry.cname, 3622 Naming.args_cname)) 3623 self.star_arg.entry.xdecref_cleanup = 0 3624 3625 def generate_tuple_and_keyword_parsing_code(self, args, success_label, code): 3626 argtuple_error_label = code.new_label("argtuple_error") 3627 3628 positional_args = [] 3629 required_kw_only_args = [] 3630 optional_kw_only_args = [] 3631 for arg in args: 3632 if arg.is_generic: 3633 if arg.default: 3634 if not arg.is_self_arg and not arg.is_type_arg: 3635 if arg.kw_only: 3636 optional_kw_only_args.append(arg) 3637 else: 3638 positional_args.append(arg) 3639 elif arg.kw_only: 3640 required_kw_only_args.append(arg) 3641 elif not arg.is_self_arg and not arg.is_type_arg: 3642 positional_args.append(arg) 3643 3644 # sort required kw-only args before optional ones to avoid special 3645 # cases in the unpacking code 3646 kw_only_args = required_kw_only_args + optional_kw_only_args 3647 3648 min_positional_args = self.num_required_args - self.num_required_kw_args 3649 if len(args) > 0 and (args[0].is_self_arg or args[0].is_type_arg): 3650 min_positional_args -= 1 3651 max_positional_args = len(positional_args) 3652 has_fixed_positional_count = not self.star_arg and \ 3653 min_positional_args == max_positional_args 3654 has_kw_only_args = bool(kw_only_args) 3655 3656 if self.starstar_arg or self.star_arg: 3657 self.generate_stararg_init_code(max_positional_args, code) 3658 3659 code.putln('{') 3660 all_args = tuple(positional_args) + tuple(kw_only_args) 3661 code.putln("static PyObject **%s[] = {%s,0};" % ( 3662 Naming.pykwdlist_cname, 3663 ','.join(['&%s' % code.intern_identifier(arg.name) 3664 for arg in all_args]))) 3665 3666 # Before being converted and assigned to the target variables, 3667 # borrowed references to all unpacked argument values are 3668 # collected into a local PyObject* array called "values", 3669 # regardless if they were taken from default arguments, 3670 # positional arguments or keyword arguments. Note that 3671 # C-typed default arguments are handled at conversion time, 3672 # so their array value is NULL in the end if no argument 3673 # was passed for them. 3674 self.generate_argument_values_setup_code(all_args, code) 3675 3676 # --- optimised code when we receive keyword arguments 3677 code.putln("if (%s(%s)) {" % ( 3678 (self.num_required_kw_args > 0) and "likely" or "unlikely", 3679 Naming.kwds_cname)) 3680 self.generate_keyword_unpacking_code( 3681 min_positional_args, max_positional_args, 3682 has_fixed_positional_count, has_kw_only_args, 3683 all_args, argtuple_error_label, code) 3684 3685 # --- optimised code when we do not receive any keyword arguments 3686 if (self.num_required_kw_args and min_positional_args > 0) or min_positional_args == max_positional_args: 3687 # Python raises arg tuple related errors first, so we must 3688 # check the length here 3689 if min_positional_args == max_positional_args and not self.star_arg: 3690 compare = '!=' 3691 else: 3692 compare = '<' 3693 code.putln('} else if (PyTuple_GET_SIZE(%s) %s %d) {' % ( 3694 Naming.args_cname, compare, min_positional_args)) 3695 code.put_goto(argtuple_error_label) 3696 3697 if self.num_required_kw_args: 3698 # pure error case: keywords required but not passed 3699 if max_positional_args > min_positional_args and not self.star_arg: 3700 code.putln('} else if (PyTuple_GET_SIZE(%s) > %d) {' % ( 3701 Naming.args_cname, max_positional_args)) 3702 code.put_goto(argtuple_error_label) 3703 code.putln('} else {') 3704 for i, arg in enumerate(kw_only_args): 3705 if not arg.default: 3706 pystring_cname = code.intern_identifier(arg.name) 3707 # required keyword-only argument missing 3708 code.globalstate.use_utility_code( 3709 UtilityCode.load_cached("RaiseKeywordRequired", "FunctionArguments.c")) 3710 code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' % ( 3711 self.name, 3712 pystring_cname)) 3713 code.putln(code.error_goto(self.pos)) 3714 break 3715 3716 else: 3717 # optimised tuple unpacking code 3718 code.putln('} else {') 3719 if min_positional_args == max_positional_args: 3720 # parse the exact number of positional arguments from 3721 # the args tuple 3722 for i, arg in enumerate(positional_args): 3723 code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % (i, Naming.args_cname, i)) 3724 else: 3725 # parse the positional arguments from the variable length 3726 # args tuple and reject illegal argument tuple sizes 3727 code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname) 3728 if self.star_arg: 3729 code.putln('default:') 3730 reversed_args = list(enumerate(positional_args))[::-1] 3731 for i, arg in reversed_args: 3732 if i >= min_positional_args-1: 3733 if i != reversed_args[0][0]: 3734 code.putln('CYTHON_FALLTHROUGH;') 3735 code.put('case %2d: ' % (i+1)) 3736 code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % (i, Naming.args_cname, i)) 3737 if min_positional_args == 0: 3738 code.putln('CYTHON_FALLTHROUGH;') 3739 code.put('case 0: ') 3740 code.putln('break;') 3741 if self.star_arg: 3742 if min_positional_args: 3743 for i in range(min_positional_args-1, -1, -1): 3744 code.putln('case %2d:' % i) 3745 code.put_goto(argtuple_error_label) 3746 else: 3747 code.put('default: ') 3748 code.put_goto(argtuple_error_label) 3749 code.putln('}') 3750 3751 code.putln('}') # end of the conditional unpacking blocks 3752 3753 # Convert arg values to their final type and assign them. 3754 # Also inject non-Python default arguments, which do cannot 3755 # live in the values[] array. 3756 for i, arg in enumerate(all_args): 3757 self.generate_arg_assignment(arg, "values[%d]" % i, code) 3758 3759 code.putln('}') # end of the whole argument unpacking block 3760 3761 if code.label_used(argtuple_error_label): 3762 code.put_goto(success_label) 3763 code.put_label(argtuple_error_label) 3764 code.globalstate.use_utility_code( 3765 UtilityCode.load_cached("RaiseArgTupleInvalid", "FunctionArguments.c")) 3766 code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, PyTuple_GET_SIZE(%s)); ' % ( 3767 self.name, has_fixed_positional_count, 3768 min_positional_args, max_positional_args, 3769 Naming.args_cname)) 3770 code.putln(code.error_goto(self.pos)) 3771 3772 def generate_arg_assignment(self, arg, item, code): 3773 if arg.type.is_pyobject: 3774 # Python default arguments were already stored in 'item' at the very beginning 3775 if arg.is_generic: 3776 item = PyrexTypes.typecast(arg.type, PyrexTypes.py_object_type, item) 3777 entry = arg.entry 3778 code.putln("%s = %s;" % (entry.cname, item)) 3779 else: 3780 if arg.type.from_py_function: 3781 if arg.default: 3782 # C-typed default arguments must be handled here 3783 code.putln('if (%s) {' % item) 3784 code.putln(arg.type.from_py_call_code( 3785 item, arg.entry.cname, arg.pos, code)) 3786 if arg.default: 3787 code.putln('} else {') 3788 code.putln("%s = %s;" % ( 3789 arg.entry.cname, 3790 arg.calculate_default_value_code(code))) 3791 if arg.type.is_memoryviewslice: 3792 code.put_incref_memoryviewslice(arg.entry.cname, 3793 have_gil=True) 3794 code.putln('}') 3795 else: 3796 error(arg.pos, "Cannot convert Python object argument to type '%s'" % arg.type) 3797 3798 def generate_stararg_init_code(self, max_positional_args, code): 3799 if self.starstar_arg: 3800 self.starstar_arg.entry.xdecref_cleanup = 0 3801 code.putln('%s = PyDict_New(); if (unlikely(!%s)) return %s;' % ( 3802 self.starstar_arg.entry.cname, 3803 self.starstar_arg.entry.cname, 3804 self.error_value())) 3805 code.put_gotref(self.starstar_arg.entry.cname) 3806 if self.star_arg: 3807 self.star_arg.entry.xdecref_cleanup = 0 3808 code.putln('if (PyTuple_GET_SIZE(%s) > %d) {' % ( 3809 Naming.args_cname, 3810 max_positional_args)) 3811 code.putln('%s = PyTuple_GetSlice(%s, %d, PyTuple_GET_SIZE(%s));' % ( 3812 self.star_arg.entry.cname, Naming.args_cname, 3813 max_positional_args, Naming.args_cname)) 3814 code.putln("if (unlikely(!%s)) {" % self.star_arg.entry.cname) 3815 if self.starstar_arg: 3816 code.put_decref_clear(self.starstar_arg.entry.cname, py_object_type) 3817 code.put_finish_refcount_context() 3818 code.putln('return %s;' % self.error_value()) 3819 code.putln('}') 3820 code.put_gotref(self.star_arg.entry.cname) 3821 code.putln('} else {') 3822 code.put("%s = %s; " % (self.star_arg.entry.cname, Naming.empty_tuple)) 3823 code.put_incref(Naming.empty_tuple, py_object_type) 3824 code.putln('}') 3825 3826 def generate_argument_values_setup_code(self, args, code): 3827 max_args = len(args) 3828 # the 'values' array collects borrowed references to arguments 3829 # before doing any type coercion etc. 3830 code.putln("PyObject* values[%d] = {%s};" % ( 3831 max_args, ','.join('0'*max_args))) 3832 3833 if self.target.defaults_struct: 3834 code.putln('%s *%s = __Pyx_CyFunction_Defaults(%s, %s);' % ( 3835 self.target.defaults_struct, Naming.dynamic_args_cname, 3836 self.target.defaults_struct, Naming.self_cname)) 3837 3838 # assign borrowed Python default values to the values array, 3839 # so that they can be overwritten by received arguments below 3840 for i, arg in enumerate(args): 3841 if arg.default and arg.type.is_pyobject: 3842 default_value = arg.calculate_default_value_code(code) 3843 code.putln('values[%d] = %s;' % (i, arg.type.as_pyobject(default_value))) 3844 3845 def generate_keyword_unpacking_code(self, min_positional_args, max_positional_args, 3846 has_fixed_positional_count, has_kw_only_args, 3847 all_args, argtuple_error_label, code): 3848 code.putln('Py_ssize_t kw_args;') 3849 code.putln('const Py_ssize_t pos_args = PyTuple_GET_SIZE(%s);' % Naming.args_cname) 3850 # copy the values from the args tuple and check that it's not too long 3851 code.putln('switch (pos_args) {') 3852 if self.star_arg: 3853 code.putln('default:') 3854 for i in range(max_positional_args-1, -1, -1): 3855 code.put('case %2d: ' % (i+1)) 3856 code.putln("values[%d] = PyTuple_GET_ITEM(%s, %d);" % ( 3857 i, Naming.args_cname, i)) 3858 code.putln('CYTHON_FALLTHROUGH;') 3859 code.putln('case 0: break;') 3860 if not self.star_arg: 3861 code.put('default: ') # more arguments than allowed 3862 code.put_goto(argtuple_error_label) 3863 code.putln('}') 3864 3865 # The code above is very often (but not always) the same as 3866 # the optimised non-kwargs tuple unpacking code, so we keep 3867 # the code block above at the very top, before the following 3868 # 'external' PyDict_Size() call, to make it easy for the C 3869 # compiler to merge the two separate tuple unpacking 3870 # implementations into one when they turn out to be identical. 3871 3872 # If we received kwargs, fill up the positional/required 3873 # arguments with values from the kw dict 3874 code.putln('kw_args = PyDict_Size(%s);' % Naming.kwds_cname) 3875 if self.num_required_args or max_positional_args > 0: 3876 last_required_arg = -1 3877 for i, arg in enumerate(all_args): 3878 if not arg.default: 3879 last_required_arg = i 3880 if last_required_arg < max_positional_args: 3881 last_required_arg = max_positional_args-1 3882 if max_positional_args > 0: 3883 code.putln('switch (pos_args) {') 3884 for i, arg in enumerate(all_args[:last_required_arg+1]): 3885 if max_positional_args > 0 and i <= max_positional_args: 3886 if i != 0: 3887 code.putln('CYTHON_FALLTHROUGH;') 3888 if self.star_arg and i == max_positional_args: 3889 code.putln('default:') 3890 else: 3891 code.putln('case %2d:' % i) 3892 pystring_cname = code.intern_identifier(arg.name) 3893 if arg.default: 3894 if arg.kw_only: 3895 # optional kw-only args are handled separately below 3896 continue 3897 code.putln('if (kw_args > 0) {') 3898 # don't overwrite default argument 3899 code.putln('PyObject* value = __Pyx_PyDict_GetItemStr(%s, %s);' % ( 3900 Naming.kwds_cname, pystring_cname)) 3901 code.putln('if (value) { values[%d] = value; kw_args--; }' % i) 3902 code.putln('}') 3903 else: 3904 code.putln('if (likely((values[%d] = __Pyx_PyDict_GetItemStr(%s, %s)) != 0)) kw_args--;' % ( 3905 i, Naming.kwds_cname, pystring_cname)) 3906 if i < min_positional_args: 3907 if i == 0: 3908 # special case: we know arg 0 is missing 3909 code.put('else ') 3910 code.put_goto(argtuple_error_label) 3911 else: 3912 # print the correct number of values (args or 3913 # kwargs) that were passed into positional 3914 # arguments up to this point 3915 code.putln('else {') 3916 code.globalstate.use_utility_code( 3917 UtilityCode.load_cached("RaiseArgTupleInvalid", "FunctionArguments.c")) 3918 code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, %d); ' % ( 3919 self.name, has_fixed_positional_count, 3920 min_positional_args, max_positional_args, i)) 3921 code.putln(code.error_goto(self.pos)) 3922 code.putln('}') 3923 elif arg.kw_only: 3924 code.putln('else {') 3925 code.globalstate.use_utility_code( 3926 UtilityCode.load_cached("RaiseKeywordRequired", "FunctionArguments.c")) 3927 code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' % ( 3928 self.name, pystring_cname)) 3929 code.putln(code.error_goto(self.pos)) 3930 code.putln('}') 3931 if max_positional_args > 0: 3932 code.putln('}') 3933 3934 if has_kw_only_args: 3935 # unpack optional keyword-only arguments separately because 3936 # checking for interned strings in a dict is faster than iterating 3937 self.generate_optional_kwonly_args_unpacking_code(all_args, code) 3938 3939 code.putln('if (unlikely(kw_args > 0)) {') 3940 # non-positional/-required kw args left in dict: default args, 3941 # kw-only args, **kwargs or error 3942 # 3943 # This is sort of a catch-all: except for checking required 3944 # arguments, this will always do the right thing for unpacking 3945 # keyword arguments, so that we can concentrate on optimising 3946 # common cases above. 3947 if max_positional_args == 0: 3948 pos_arg_count = "0" 3949 elif self.star_arg: 3950 code.putln("const Py_ssize_t used_pos_args = (pos_args < %d) ? pos_args : %d;" % ( 3951 max_positional_args, max_positional_args)) 3952 pos_arg_count = "used_pos_args" 3953 else: 3954 pos_arg_count = "pos_args" 3955 code.globalstate.use_utility_code( 3956 UtilityCode.load_cached("ParseKeywords", "FunctionArguments.c")) 3957 code.putln('if (unlikely(__Pyx_ParseOptionalKeywords(%s, %s, %s, values, %s, "%s") < 0)) %s' % ( 3958 Naming.kwds_cname, 3959 Naming.pykwdlist_cname, 3960 self.starstar_arg and self.starstar_arg.entry.cname or '0', 3961 pos_arg_count, 3962 self.name, 3963 code.error_goto(self.pos))) 3964 code.putln('}') 3965 3966 def generate_optional_kwonly_args_unpacking_code(self, all_args, code): 3967 optional_args = [] 3968 first_optional_arg = -1 3969 for i, arg in enumerate(all_args): 3970 if not arg.kw_only or not arg.default: 3971 continue 3972 if not optional_args: 3973 first_optional_arg = i 3974 optional_args.append(arg.name) 3975 if optional_args: 3976 if len(optional_args) > 1: 3977 # if we receive more than the named kwargs, we either have **kwargs 3978 # (in which case we must iterate anyway) or it's an error (which we 3979 # also handle during iteration) => skip this part if there are more 3980 code.putln('if (kw_args > 0 && %s(kw_args <= %d)) {' % ( 3981 not self.starstar_arg and 'likely' or '', 3982 len(optional_args))) 3983 code.putln('Py_ssize_t index;') 3984 # not unrolling the loop here reduces the C code overhead 3985 code.putln('for (index = %d; index < %d && kw_args > 0; index++) {' % ( 3986 first_optional_arg, first_optional_arg + len(optional_args))) 3987 else: 3988 code.putln('if (kw_args == 1) {') 3989 code.putln('const Py_ssize_t index = %d;' % first_optional_arg) 3990 code.putln('PyObject* value = __Pyx_PyDict_GetItemStr(%s, *%s[index]);' % ( 3991 Naming.kwds_cname, Naming.pykwdlist_cname)) 3992 code.putln('if (value) { values[index] = value; kw_args--; }') 3993 if len(optional_args) > 1: 3994 code.putln('}') 3995 code.putln('}') 3996 3997 def generate_argument_conversion_code(self, code): 3998 # Generate code to convert arguments from signature type to 3999 # declared type, if needed. Also copies signature arguments 4000 # into closure fields. 4001 for arg in self.args: 4002 if arg.needs_conversion: 4003 self.generate_arg_conversion(arg, code) 4004 4005 def generate_arg_conversion(self, arg, code): 4006 # Generate conversion code for one argument. 4007 old_type = arg.hdr_type 4008 new_type = arg.type 4009 if old_type.is_pyobject: 4010 if arg.default: 4011 code.putln("if (%s) {" % arg.hdr_cname) 4012 else: 4013 code.putln("assert(%s); {" % arg.hdr_cname) 4014 self.generate_arg_conversion_from_pyobject(arg, code) 4015 code.putln("}") 4016 elif new_type.is_pyobject: 4017 self.generate_arg_conversion_to_pyobject(arg, code) 4018 else: 4019 if new_type.assignable_from(old_type): 4020 code.putln("%s = %s;" % (arg.entry.cname, arg.hdr_cname)) 4021 else: 4022 error(arg.pos, "Cannot convert 1 argument from '%s' to '%s'" % (old_type, new_type)) 4023 4024 def generate_arg_conversion_from_pyobject(self, arg, code): 4025 new_type = arg.type 4026 # copied from CoerceFromPyTypeNode 4027 if new_type.from_py_function: 4028 code.putln(new_type.from_py_call_code( 4029 arg.hdr_cname, 4030 arg.entry.cname, 4031 arg.pos, 4032 code, 4033 )) 4034 else: 4035 error(arg.pos, "Cannot convert Python object argument to type '%s'" % new_type) 4036 4037 def generate_arg_conversion_to_pyobject(self, arg, code): 4038 old_type = arg.hdr_type 4039 func = old_type.to_py_function 4040 if func: 4041 code.putln("%s = %s(%s); %s" % ( 4042 arg.entry.cname, 4043 func, 4044 arg.hdr_cname, 4045 code.error_goto_if_null(arg.entry.cname, arg.pos))) 4046 code.put_var_gotref(arg.entry) 4047 else: 4048 error(arg.pos, "Cannot convert argument of type '%s' to Python object" % old_type) 4049 4050 def generate_argument_type_tests(self, code): 4051 # Generate type tests for args whose signature 4052 # type is PyObject * and whose declared type is 4053 # a subtype thereof. 4054 for arg in self.args: 4055 if arg.needs_type_test: 4056 self.generate_arg_type_test(arg, code) 4057 elif not arg.accept_none and (arg.type.is_pyobject or 4058 arg.type.is_buffer or 4059 arg.type.is_memoryviewslice): 4060 self.generate_arg_none_check(arg, code) 4061 4062 def error_value(self): 4063 return self.signature.error_value 4064 4065 4066class GeneratorDefNode(DefNode): 4067 # Generator function node that creates a new generator instance when called. 4068 # 4069 # gbody GeneratorBodyDefNode the function implementing the generator 4070 # 4071 4072 is_generator = True 4073 is_coroutine = False 4074 is_iterable_coroutine = False 4075 is_asyncgen = False 4076 gen_type_name = 'Generator' 4077 needs_closure = True 4078 4079 child_attrs = DefNode.child_attrs + ["gbody"] 4080 4081 def __init__(self, pos, **kwargs): 4082 # XXX: don't actually needs a body 4083 kwargs['body'] = StatListNode(pos, stats=[], is_terminator=True) 4084 super(GeneratorDefNode, self).__init__(pos, **kwargs) 4085 4086 def analyse_declarations(self, env): 4087 super(GeneratorDefNode, self).analyse_declarations(env) 4088 self.gbody.local_scope = self.local_scope 4089 self.gbody.analyse_declarations(env) 4090 4091 def generate_function_body(self, env, code): 4092 body_cname = self.gbody.entry.func_cname 4093 name = code.intern_identifier(self.name) 4094 qualname = code.intern_identifier(self.qualname) 4095 module_name = code.intern_identifier(self.module_name) 4096 4097 code.putln('{') 4098 code.putln('__pyx_CoroutineObject *gen = __Pyx_%s_New(' 4099 '(__pyx_coroutine_body_t) %s, %s, (PyObject *) %s, %s, %s, %s); %s' % ( 4100 self.gen_type_name, 4101 body_cname, self.code_object.calculate_result_code(code) if self.code_object else 'NULL', 4102 Naming.cur_scope_cname, name, qualname, module_name, 4103 code.error_goto_if_null('gen', self.pos))) 4104 code.put_decref(Naming.cur_scope_cname, py_object_type) 4105 if self.requires_classobj: 4106 classobj_cname = 'gen->classobj' 4107 code.putln('%s = __Pyx_CyFunction_GetClassObj(%s);' % ( 4108 classobj_cname, Naming.self_cname)) 4109 code.put_incref(classobj_cname, py_object_type) 4110 code.put_giveref(classobj_cname) 4111 code.put_finish_refcount_context() 4112 code.putln('return (PyObject *) gen;') 4113 code.putln('}') 4114 4115 def generate_function_definitions(self, env, code): 4116 env.use_utility_code(UtilityCode.load_cached(self.gen_type_name, "Coroutine.c")) 4117 self.gbody.generate_function_header(code, proto=True) 4118 super(GeneratorDefNode, self).generate_function_definitions(env, code) 4119 self.gbody.generate_function_definitions(env, code) 4120 4121 4122class AsyncDefNode(GeneratorDefNode): 4123 gen_type_name = 'Coroutine' 4124 is_coroutine = True 4125 4126 4127class IterableAsyncDefNode(AsyncDefNode): 4128 gen_type_name = 'IterableCoroutine' 4129 is_iterable_coroutine = True 4130 4131 4132class AsyncGenNode(AsyncDefNode): 4133 gen_type_name = 'AsyncGen' 4134 is_asyncgen = True 4135 4136 4137class GeneratorBodyDefNode(DefNode): 4138 # Main code body of a generator implemented as a DefNode. 4139 # 4140 4141 is_generator_body = True 4142 is_inlined = False 4143 is_async_gen_body = False 4144 inlined_comprehension_type = None # container type for inlined comprehensions 4145 4146 def __init__(self, pos=None, name=None, body=None, is_async_gen_body=False): 4147 super(GeneratorBodyDefNode, self).__init__( 4148 pos=pos, body=body, name=name, is_async_gen_body=is_async_gen_body, 4149 doc=None, args=[], star_arg=None, starstar_arg=None) 4150 4151 def declare_generator_body(self, env): 4152 prefix = env.next_id(env.scope_prefix) 4153 name = env.next_id('generator') 4154 cname = Naming.genbody_prefix + prefix + name 4155 entry = env.declare_var(None, py_object_type, self.pos, 4156 cname=cname, visibility='private') 4157 entry.func_cname = cname 4158 entry.qualified_name = EncodedString(self.name) 4159 # Work-around for https://github.com/cython/cython/issues/1699 4160 # We don't currently determine whether the generator entry is used or not, 4161 # so mark it as used to avoid false warnings. 4162 entry.used = True 4163 self.entry = entry 4164 4165 def analyse_declarations(self, env): 4166 self.analyse_argument_types(env) 4167 self.declare_generator_body(env) 4168 4169 def generate_function_header(self, code, proto=False): 4170 header = "static PyObject *%s(__pyx_CoroutineObject *%s, CYTHON_UNUSED PyThreadState *%s, PyObject *%s)" % ( 4171 self.entry.func_cname, 4172 Naming.generator_cname, 4173 Naming.local_tstate_cname, 4174 Naming.sent_value_cname) 4175 if proto: 4176 code.putln('%s; /* proto */' % header) 4177 else: 4178 code.putln('%s /* generator body */\n{' % header) 4179 4180 def generate_function_definitions(self, env, code): 4181 lenv = self.local_scope 4182 4183 # Generate closure function definitions 4184 self.body.generate_function_definitions(lenv, code) 4185 4186 # Generate C code for header and body of function 4187 code.enter_cfunc_scope(lenv) 4188 code.return_from_error_cleanup_label = code.new_label() 4189 4190 # ----- Top-level constants used by this function 4191 code.mark_pos(self.pos) 4192 self.generate_cached_builtins_decls(lenv, code) 4193 # ----- Function header 4194 code.putln("") 4195 self.generate_function_header(code) 4196 closure_init_code = code.insertion_point() 4197 # ----- Local variables 4198 code.putln("PyObject *%s = NULL;" % Naming.retval_cname) 4199 tempvardecl_code = code.insertion_point() 4200 code.put_declare_refcount_context() 4201 code.put_setup_refcount_context(self.entry.name or self.entry.qualified_name) 4202 profile = code.globalstate.directives['profile'] 4203 linetrace = code.globalstate.directives['linetrace'] 4204 if profile or linetrace: 4205 tempvardecl_code.put_trace_declarations() 4206 code.funcstate.can_trace = True 4207 code_object = self.code_object.calculate_result_code(code) if self.code_object else None 4208 code.put_trace_frame_init(code_object) 4209 4210 # ----- Resume switch point. 4211 code.funcstate.init_closure_temps(lenv.scope_class.type.scope) 4212 resume_code = code.insertion_point() 4213 first_run_label = code.new_label('first_run') 4214 code.use_label(first_run_label) 4215 code.put_label(first_run_label) 4216 code.putln('%s' % 4217 (code.error_goto_if_null(Naming.sent_value_cname, self.pos))) 4218 4219 # ----- prepare target container for inlined comprehension 4220 if self.is_inlined and self.inlined_comprehension_type is not None: 4221 target_type = self.inlined_comprehension_type 4222 if target_type is Builtin.list_type: 4223 comp_init = 'PyList_New(0)' 4224 elif target_type is Builtin.set_type: 4225 comp_init = 'PySet_New(NULL)' 4226 elif target_type is Builtin.dict_type: 4227 comp_init = 'PyDict_New()' 4228 else: 4229 raise InternalError( 4230 "invalid type of inlined comprehension: %s" % target_type) 4231 code.putln("%s = %s; %s" % ( 4232 Naming.retval_cname, comp_init, 4233 code.error_goto_if_null(Naming.retval_cname, self.pos))) 4234 code.put_gotref(Naming.retval_cname) 4235 4236 # ----- Function body 4237 self.generate_function_body(env, code) 4238 # ----- Closure initialization 4239 if lenv.scope_class.type.scope.var_entries: 4240 closure_init_code.putln('%s = %s;' % ( 4241 lenv.scope_class.type.declaration_code(Naming.cur_scope_cname), 4242 lenv.scope_class.type.cast_code('%s->closure' % 4243 Naming.generator_cname))) 4244 # FIXME: this silences a potential "unused" warning => try to avoid unused closures in more cases 4245 code.putln("CYTHON_MAYBE_UNUSED_VAR(%s);" % Naming.cur_scope_cname) 4246 4247 if profile or linetrace: 4248 code.funcstate.can_trace = False 4249 4250 code.mark_pos(self.pos) 4251 code.putln("") 4252 code.putln("/* function exit code */") 4253 4254 # on normal generator termination, we do not take the exception propagation 4255 # path: no traceback info is required and not creating it is much faster 4256 if not self.is_inlined and not self.body.is_terminator: 4257 if self.is_async_gen_body: 4258 code.globalstate.use_utility_code( 4259 UtilityCode.load_cached("StopAsyncIteration", "Coroutine.c")) 4260 code.putln('PyErr_SetNone(%s);' % ( 4261 '__Pyx_PyExc_StopAsyncIteration' if self.is_async_gen_body else 'PyExc_StopIteration')) 4262 # ----- Error cleanup 4263 if code.label_used(code.error_label): 4264 if not self.body.is_terminator: 4265 code.put_goto(code.return_label) 4266 code.put_label(code.error_label) 4267 if self.is_inlined and self.inlined_comprehension_type is not None: 4268 code.put_xdecref_clear(Naming.retval_cname, py_object_type) 4269 if Future.generator_stop in env.global_scope().context.future_directives: 4270 # PEP 479: turn accidental StopIteration exceptions into a RuntimeError 4271 code.globalstate.use_utility_code(UtilityCode.load_cached("pep479", "Coroutine.c")) 4272 code.putln("__Pyx_Generator_Replace_StopIteration(%d);" % bool(self.is_async_gen_body)) 4273 for cname, type in code.funcstate.all_managed_temps(): 4274 code.put_xdecref(cname, type) 4275 code.put_add_traceback(self.entry.qualified_name) 4276 4277 # ----- Non-error return cleanup 4278 code.put_label(code.return_label) 4279 if self.is_inlined: 4280 code.put_xgiveref(Naming.retval_cname) 4281 else: 4282 code.put_xdecref_clear(Naming.retval_cname, py_object_type) 4283 # For Py3.7, clearing is already done below. 4284 code.putln("#if !CYTHON_USE_EXC_INFO_STACK") 4285 code.putln("__Pyx_Coroutine_ResetAndClearException(%s);" % Naming.generator_cname) 4286 code.putln("#endif") 4287 code.putln('%s->resume_label = -1;' % Naming.generator_cname) 4288 # clean up as early as possible to help breaking any reference cycles 4289 code.putln('__Pyx_Coroutine_clear((PyObject*)%s);' % Naming.generator_cname) 4290 if profile or linetrace: 4291 code.put_trace_return(Naming.retval_cname, 4292 nogil=not code.funcstate.gil_owned) 4293 code.put_finish_refcount_context() 4294 code.putln("return %s;" % Naming.retval_cname) 4295 code.putln("}") 4296 4297 # ----- Go back and insert temp variable declarations 4298 tempvardecl_code.put_temp_declarations(code.funcstate) 4299 # ----- Generator resume code 4300 if profile or linetrace: 4301 resume_code.put_trace_call(self.entry.qualified_name, self.pos, 4302 nogil=not code.funcstate.gil_owned) 4303 resume_code.putln("switch (%s->resume_label) {" % ( 4304 Naming.generator_cname)) 4305 4306 resume_code.putln("case 0: goto %s;" % first_run_label) 4307 4308 for i, label in code.yield_labels: 4309 resume_code.putln("case %d: goto %s;" % (i, label)) 4310 resume_code.putln("default: /* CPython raises the right error here */") 4311 if profile or linetrace: 4312 resume_code.put_trace_return("Py_None", 4313 nogil=not code.funcstate.gil_owned) 4314 resume_code.put_finish_refcount_context() 4315 resume_code.putln("return NULL;") 4316 resume_code.putln("}") 4317 4318 code.exit_cfunc_scope() 4319 4320 4321class OverrideCheckNode(StatNode): 4322 # A Node for dispatching to the def method if it 4323 # is overridden. 4324 # 4325 # py_func 4326 # 4327 # args 4328 # func_temp 4329 # body 4330 4331 child_attrs = ['body'] 4332 4333 body = None 4334 4335 def analyse_expressions(self, env): 4336 self.args = env.arg_entries 4337 if self.py_func.is_module_scope: 4338 first_arg = 0 4339 else: 4340 first_arg = 1 4341 from . import ExprNodes 4342 self.func_node = ExprNodes.RawCNameExprNode(self.pos, py_object_type) 4343 call_node = ExprNodes.SimpleCallNode( 4344 self.pos, function=self.func_node, 4345 args=[ExprNodes.NameNode(self.pos, name=arg.name) 4346 for arg in self.args[first_arg:]]) 4347 if env.return_type.is_void or env.return_type.is_returncode: 4348 self.body = StatListNode(self.pos, stats=[ 4349 ExprStatNode(self.pos, expr=call_node), 4350 ReturnStatNode(self.pos, value=None)]) 4351 else: 4352 self.body = ReturnStatNode(self.pos, value=call_node) 4353 self.body = self.body.analyse_expressions(env) 4354 return self 4355 4356 def generate_execution_code(self, code): 4357 interned_attr_cname = code.intern_identifier(self.py_func.entry.name) 4358 # Check to see if we are an extension type 4359 if self.py_func.is_module_scope: 4360 self_arg = "((PyObject *)%s)" % Naming.module_cname 4361 else: 4362 self_arg = "((PyObject *)%s)" % self.args[0].cname 4363 code.putln("/* Check if called by wrapper */") 4364 code.putln("if (unlikely(%s)) ;" % Naming.skip_dispatch_cname) 4365 code.putln("/* Check if overridden in Python */") 4366 if self.py_func.is_module_scope: 4367 code.putln("else {") 4368 else: 4369 code.putln("else if (unlikely((Py_TYPE(%s)->tp_dictoffset != 0)" 4370 " || (Py_TYPE(%s)->tp_flags & (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)))) {" % ( 4371 self_arg, self_arg)) 4372 4373 code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS") 4374 code.globalstate.use_utility_code( 4375 UtilityCode.load_cached("PyDictVersioning", "ObjectHandling.c")) 4376 # TODO: remove the object dict version check by 'inlining' the getattr implementation for methods. 4377 # This would allow checking the dict versions around _PyType_Lookup() if it returns a descriptor, 4378 # and would (tada!) make this check a pure type based thing instead of supporting only a single 4379 # instance at a time. 4380 code.putln("static PY_UINT64_T %s = __PYX_DICT_VERSION_INIT, %s = __PYX_DICT_VERSION_INIT;" % ( 4381 Naming.tp_dict_version_temp, Naming.obj_dict_version_temp)) 4382 code.putln("if (unlikely(!__Pyx_object_dict_version_matches(%s, %s, %s))) {" % ( 4383 self_arg, Naming.tp_dict_version_temp, Naming.obj_dict_version_temp)) 4384 code.putln("PY_UINT64_T %s = __Pyx_get_tp_dict_version(%s);" % ( 4385 Naming.type_dict_guard_temp, self_arg)) 4386 code.putln("#endif") 4387 4388 func_node_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True) 4389 self.func_node.set_cname(func_node_temp) 4390 # need to get attribute manually--scope would return cdef method 4391 code.globalstate.use_utility_code( 4392 UtilityCode.load_cached("PyObjectGetAttrStr", "ObjectHandling.c")) 4393 err = code.error_goto_if_null(func_node_temp, self.pos) 4394 code.putln("%s = __Pyx_PyObject_GetAttrStr(%s, %s); %s" % ( 4395 func_node_temp, self_arg, interned_attr_cname, err)) 4396 code.put_gotref(func_node_temp) 4397 4398 is_builtin_function_or_method = "PyCFunction_Check(%s)" % func_node_temp 4399 is_overridden = "(PyCFunction_GET_FUNCTION(%s) != (PyCFunction)(void*)%s)" % ( 4400 func_node_temp, self.py_func.entry.func_cname) 4401 code.putln("if (!%s || %s) {" % (is_builtin_function_or_method, is_overridden)) 4402 self.body.generate_execution_code(code) 4403 code.putln("}") 4404 4405 # NOTE: it's not 100% sure that we catch the exact versions here that were used for the lookup, 4406 # but it is very unlikely that the versions change during lookup, and the type dict safe guard 4407 # should increase the chance of detecting such a case. 4408 code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS") 4409 code.putln("%s = __Pyx_get_tp_dict_version(%s);" % ( 4410 Naming.tp_dict_version_temp, self_arg)) 4411 code.putln("%s = __Pyx_get_object_dict_version(%s);" % ( 4412 Naming.obj_dict_version_temp, self_arg)) 4413 # Safety check that the type dict didn't change during the lookup. Since CPython looks up the 4414 # attribute (descriptor) first in the type dict and then in the instance dict or through the 4415 # descriptor, the only really far-away lookup when we get here is one in the type dict. So we 4416 # double check the type dict version before and afterwards to guard against later changes of 4417 # the type dict during the lookup process. 4418 code.putln("if (unlikely(%s != %s)) {" % ( 4419 Naming.type_dict_guard_temp, Naming.tp_dict_version_temp)) 4420 code.putln("%s = %s = __PYX_DICT_VERSION_INIT;" % ( 4421 Naming.tp_dict_version_temp, Naming.obj_dict_version_temp)) 4422 code.putln("}") 4423 code.putln("#endif") 4424 4425 code.put_decref_clear(func_node_temp, PyrexTypes.py_object_type) 4426 code.funcstate.release_temp(func_node_temp) 4427 4428 code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS") 4429 code.putln("}") 4430 code.putln("#endif") 4431 4432 code.putln("}") 4433 4434 4435class ClassDefNode(StatNode, BlockNode): 4436 pass 4437 4438 4439class PyClassDefNode(ClassDefNode): 4440 # A Python class definition. 4441 # 4442 # name EncodedString Name of the class 4443 # doc string or None 4444 # body StatNode Attribute definition code 4445 # entry Symtab.Entry 4446 # scope PyClassScope 4447 # decorators [DecoratorNode] list of decorators or None 4448 # 4449 # The following subnodes are constructed internally: 4450 # 4451 # dict DictNode Class dictionary or Py3 namespace 4452 # classobj ClassNode Class object 4453 # target NameNode Variable to assign class object to 4454 4455 child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "class_result", 4456 "target", "class_cell", "decorators"] 4457 decorators = None 4458 class_result = None 4459 is_py3_style_class = False # Python3 style class (kwargs) 4460 metaclass = None 4461 mkw = None 4462 4463 def __init__(self, pos, name, bases, doc, body, decorators=None, 4464 keyword_args=None, force_py3_semantics=False): 4465 StatNode.__init__(self, pos) 4466 self.name = name 4467 self.doc = doc 4468 self.body = body 4469 self.decorators = decorators 4470 self.bases = bases 4471 from . import ExprNodes 4472 if self.doc and Options.docstrings: 4473 doc = embed_position(self.pos, self.doc) 4474 doc_node = ExprNodes.StringNode(pos, value=doc) 4475 else: 4476 doc_node = None 4477 4478 allow_py2_metaclass = not force_py3_semantics 4479 if keyword_args: 4480 allow_py2_metaclass = False 4481 self.is_py3_style_class = True 4482 if keyword_args.is_dict_literal: 4483 if keyword_args.key_value_pairs: 4484 for i, item in list(enumerate(keyword_args.key_value_pairs))[::-1]: 4485 if item.key.value == 'metaclass': 4486 if self.metaclass is not None: 4487 error(item.pos, "keyword argument 'metaclass' passed multiple times") 4488 # special case: we already know the metaclass, 4489 # so we don't need to do the "build kwargs, 4490 # find metaclass" dance at runtime 4491 self.metaclass = item.value 4492 del keyword_args.key_value_pairs[i] 4493 self.mkw = keyword_args 4494 else: 4495 assert self.metaclass is not None 4496 else: 4497 # MergedDictNode 4498 self.mkw = ExprNodes.ProxyNode(keyword_args) 4499 4500 if force_py3_semantics or self.bases or self.mkw or self.metaclass: 4501 if self.metaclass is None: 4502 if keyword_args and not keyword_args.is_dict_literal: 4503 # **kwargs may contain 'metaclass' arg 4504 mkdict = self.mkw 4505 else: 4506 mkdict = None 4507 if (not mkdict and 4508 self.bases.is_sequence_constructor and 4509 not self.bases.args): 4510 pass # no base classes => no inherited metaclass 4511 else: 4512 self.metaclass = ExprNodes.PyClassMetaclassNode( 4513 pos, class_def_node=self) 4514 needs_metaclass_calculation = False 4515 else: 4516 needs_metaclass_calculation = True 4517 4518 self.dict = ExprNodes.PyClassNamespaceNode( 4519 pos, name=name, doc=doc_node, class_def_node=self) 4520 self.classobj = ExprNodes.Py3ClassNode( 4521 pos, name=name, class_def_node=self, doc=doc_node, 4522 calculate_metaclass=needs_metaclass_calculation, 4523 allow_py2_metaclass=allow_py2_metaclass) 4524 else: 4525 # no bases, no metaclass => old style class creation 4526 self.dict = ExprNodes.DictNode(pos, key_value_pairs=[]) 4527 self.classobj = ExprNodes.ClassNode( 4528 pos, name=name, class_def_node=self, doc=doc_node) 4529 4530 self.target = ExprNodes.NameNode(pos, name=name) 4531 self.class_cell = ExprNodes.ClassCellInjectorNode(self.pos) 4532 4533 def as_cclass(self): 4534 """ 4535 Return this node as if it were declared as an extension class 4536 """ 4537 if self.is_py3_style_class: 4538 error(self.classobj.pos, "Python3 style class could not be represented as C class") 4539 return 4540 4541 from . import ExprNodes 4542 return CClassDefNode(self.pos, 4543 visibility='private', 4544 module_name=None, 4545 class_name=self.name, 4546 bases=self.bases or ExprNodes.TupleNode(self.pos, args=[]), 4547 decorators=self.decorators, 4548 body=self.body, 4549 in_pxd=False, 4550 doc=self.doc) 4551 4552 def create_scope(self, env): 4553 genv = env 4554 while genv.is_py_class_scope or genv.is_c_class_scope: 4555 genv = genv.outer_scope 4556 cenv = self.scope = PyClassScope(name=self.name, outer_scope=genv) 4557 return cenv 4558 4559 def analyse_declarations(self, env): 4560 class_result = self.classobj 4561 if self.decorators: 4562 from .ExprNodes import SimpleCallNode 4563 for decorator in self.decorators[::-1]: 4564 class_result = SimpleCallNode( 4565 decorator.pos, 4566 function=decorator.decorator, 4567 args=[class_result]) 4568 self.decorators = None 4569 self.class_result = class_result 4570 if self.bases: 4571 self.bases.analyse_declarations(env) 4572 if self.mkw: 4573 self.mkw.analyse_declarations(env) 4574 self.class_result.analyse_declarations(env) 4575 self.target.analyse_target_declaration(env) 4576 cenv = self.create_scope(env) 4577 cenv.directives = env.directives 4578 cenv.class_obj_cname = self.target.entry.cname 4579 self.body.analyse_declarations(cenv) 4580 4581 def analyse_expressions(self, env): 4582 if self.bases: 4583 self.bases = self.bases.analyse_expressions(env) 4584 if self.mkw: 4585 self.mkw = self.mkw.analyse_expressions(env) 4586 if self.metaclass: 4587 self.metaclass = self.metaclass.analyse_expressions(env) 4588 self.dict = self.dict.analyse_expressions(env) 4589 self.class_result = self.class_result.analyse_expressions(env) 4590 cenv = self.scope 4591 self.body = self.body.analyse_expressions(cenv) 4592 self.target.analyse_target_expression(env, self.classobj) 4593 self.class_cell = self.class_cell.analyse_expressions(cenv) 4594 return self 4595 4596 def generate_function_definitions(self, env, code): 4597 self.generate_lambda_definitions(self.scope, code) 4598 self.body.generate_function_definitions(self.scope, code) 4599 4600 def generate_execution_code(self, code): 4601 code.mark_pos(self.pos) 4602 code.pyclass_stack.append(self) 4603 cenv = self.scope 4604 if self.bases: 4605 self.bases.generate_evaluation_code(code) 4606 if self.mkw: 4607 self.mkw.generate_evaluation_code(code) 4608 if self.metaclass: 4609 self.metaclass.generate_evaluation_code(code) 4610 self.dict.generate_evaluation_code(code) 4611 cenv.namespace_cname = cenv.class_obj_cname = self.dict.result() 4612 4613 class_cell = self.class_cell 4614 if class_cell is not None and not class_cell.is_active: 4615 class_cell = None 4616 4617 if class_cell is not None: 4618 class_cell.generate_evaluation_code(code) 4619 self.body.generate_execution_code(code) 4620 self.class_result.generate_evaluation_code(code) 4621 if class_cell is not None: 4622 class_cell.generate_injection_code( 4623 code, self.class_result.result()) 4624 if class_cell is not None: 4625 class_cell.generate_disposal_code(code) 4626 class_cell.free_temps(code) 4627 4628 cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result() 4629 self.target.generate_assignment_code(self.class_result, code) 4630 self.dict.generate_disposal_code(code) 4631 self.dict.free_temps(code) 4632 if self.metaclass: 4633 self.metaclass.generate_disposal_code(code) 4634 self.metaclass.free_temps(code) 4635 if self.mkw: 4636 self.mkw.generate_disposal_code(code) 4637 self.mkw.free_temps(code) 4638 if self.bases: 4639 self.bases.generate_disposal_code(code) 4640 self.bases.free_temps(code) 4641 code.pyclass_stack.pop() 4642 4643 4644class CClassDefNode(ClassDefNode): 4645 # An extension type definition. 4646 # 4647 # visibility 'private' or 'public' or 'extern' 4648 # typedef_flag boolean 4649 # api boolean 4650 # module_name string or None For import of extern type objects 4651 # class_name string Unqualified name of class 4652 # as_name string or None Name to declare as in this scope 4653 # bases TupleNode Base class(es) 4654 # objstruct_name string or None Specified C name of object struct 4655 # typeobj_name string or None Specified C name of type object 4656 # check_size 'warn', 'error', 'ignore' What to do if tp_basicsize does not match 4657 # in_pxd boolean Is in a .pxd file 4658 # decorators [DecoratorNode] list of decorators or None 4659 # doc string or None 4660 # body StatNode or None 4661 # entry Symtab.Entry 4662 # base_type PyExtensionType or None 4663 # buffer_defaults_node DictNode or None Declares defaults for a buffer 4664 # buffer_defaults_pos 4665 4666 child_attrs = ["body"] 4667 buffer_defaults_node = None 4668 buffer_defaults_pos = None 4669 typedef_flag = False 4670 api = False 4671 objstruct_name = None 4672 typeobj_name = None 4673 check_size = None 4674 decorators = None 4675 shadow = False 4676 4677 def buffer_defaults(self, env): 4678 if not hasattr(self, '_buffer_defaults'): 4679 from . import Buffer 4680 if self.buffer_defaults_node: 4681 self._buffer_defaults = Buffer.analyse_buffer_options( 4682 self.buffer_defaults_pos, 4683 env, [], self.buffer_defaults_node, 4684 need_complete=False) 4685 else: 4686 self._buffer_defaults = None 4687 return self._buffer_defaults 4688 4689 def declare(self, env): 4690 if self.module_name and self.visibility != 'extern': 4691 module_path = self.module_name.split(".") 4692 home_scope = env.find_imported_module(module_path, self.pos) 4693 if not home_scope: 4694 return None 4695 else: 4696 home_scope = env 4697 4698 self.entry = home_scope.declare_c_class( 4699 name=self.class_name, 4700 pos=self.pos, 4701 defining=0, 4702 implementing=0, 4703 module_name=self.module_name, 4704 base_type=None, 4705 objstruct_cname=self.objstruct_name, 4706 typeobj_cname=self.typeobj_name, 4707 visibility=self.visibility, 4708 typedef_flag=self.typedef_flag, 4709 check_size = self.check_size, 4710 api=self.api, 4711 buffer_defaults=self.buffer_defaults(env), 4712 shadow=self.shadow) 4713 4714 def analyse_declarations(self, env): 4715 #print "CClassDefNode.analyse_declarations:", self.class_name 4716 #print "...visibility =", self.visibility 4717 #print "...module_name =", self.module_name 4718 4719 if env.in_cinclude and not self.objstruct_name: 4720 error(self.pos, "Object struct name specification required for C class defined in 'extern from' block") 4721 if self.decorators: 4722 error(self.pos, "Decorators not allowed on cdef classes (used on type '%s')" % self.class_name) 4723 self.base_type = None 4724 # Now that module imports are cached, we need to 4725 # import the modules for extern classes. 4726 if self.module_name: 4727 self.module = None 4728 for module in env.cimported_modules: 4729 if module.name == self.module_name: 4730 self.module = module 4731 if self.module is None: 4732 self.module = ModuleScope(self.module_name, None, env.context) 4733 self.module.has_extern_class = 1 4734 env.add_imported_module(self.module) 4735 4736 if self.bases.args: 4737 base = self.bases.args[0] 4738 base_type = base.analyse_as_type(env) 4739 if base_type in (PyrexTypes.c_int_type, PyrexTypes.c_long_type, PyrexTypes.c_float_type): 4740 # Use the Python rather than C variant of these types. 4741 base_type = env.lookup(base_type.sign_and_name()).type 4742 if base_type is None: 4743 error(base.pos, "First base of '%s' is not an extension type" % self.class_name) 4744 elif base_type == PyrexTypes.py_object_type: 4745 base_class_scope = None 4746 elif not base_type.is_extension_type and \ 4747 not (base_type.is_builtin_type and base_type.objstruct_cname): 4748 error(base.pos, "'%s' is not an extension type" % base_type) 4749 elif not base_type.is_complete(): 4750 error(base.pos, "Base class '%s' of type '%s' is incomplete" % ( 4751 base_type.name, self.class_name)) 4752 elif base_type.scope and base_type.scope.directives and \ 4753 base_type.is_final_type: 4754 error(base.pos, "Base class '%s' of type '%s' is final" % ( 4755 base_type, self.class_name)) 4756 elif base_type.is_builtin_type and \ 4757 base_type.name in ('tuple', 'str', 'bytes'): 4758 error(base.pos, "inheritance from PyVarObject types like '%s' is not currently supported" 4759 % base_type.name) 4760 else: 4761 self.base_type = base_type 4762 if env.directives.get('freelist', 0) > 0 and base_type != PyrexTypes.py_object_type: 4763 warning(self.pos, "freelists cannot be used on subtypes, only the base class can manage them", 1) 4764 4765 has_body = self.body is not None 4766 if has_body and self.base_type and not self.base_type.scope: 4767 # To properly initialize inherited attributes, the base type must 4768 # be analysed before this type. 4769 self.base_type.defered_declarations.append(lambda : self.analyse_declarations(env)) 4770 return 4771 4772 if self.module_name and self.visibility != 'extern': 4773 module_path = self.module_name.split(".") 4774 home_scope = env.find_imported_module(module_path, self.pos) 4775 if not home_scope: 4776 return 4777 else: 4778 home_scope = env 4779 4780 if self.visibility == 'extern': 4781 if (self.module_name == '__builtin__' and 4782 self.class_name in Builtin.builtin_types and 4783 env.qualified_name[:8] != 'cpython.'): # allow overloaded names for cimporting from cpython 4784 warning(self.pos, "%s already a builtin Cython type" % self.class_name, 1) 4785 4786 self.entry = home_scope.declare_c_class( 4787 name=self.class_name, 4788 pos=self.pos, 4789 defining=has_body and self.in_pxd, 4790 implementing=has_body and not self.in_pxd, 4791 module_name=self.module_name, 4792 base_type=self.base_type, 4793 objstruct_cname=self.objstruct_name, 4794 typeobj_cname=self.typeobj_name, 4795 check_size=self.check_size, 4796 visibility=self.visibility, 4797 typedef_flag=self.typedef_flag, 4798 api=self.api, 4799 buffer_defaults=self.buffer_defaults(env), 4800 shadow=self.shadow) 4801 4802 if self.shadow: 4803 home_scope.lookup(self.class_name).as_variable = self.entry 4804 if home_scope is not env and self.visibility == 'extern': 4805 env.add_imported_entry(self.class_name, self.entry, self.pos) 4806 self.scope = scope = self.entry.type.scope 4807 if scope is not None: 4808 scope.directives = env.directives 4809 4810 if self.doc and Options.docstrings: 4811 scope.doc = embed_position(self.pos, self.doc) 4812 4813 if has_body: 4814 self.body.analyse_declarations(scope) 4815 dict_entry = self.scope.lookup_here("__dict__") 4816 if dict_entry and dict_entry.is_variable and (not scope.defined and not scope.implemented): 4817 dict_entry.getter_cname = self.scope.mangle_internal("__dict__getter") 4818 self.scope.declare_property("__dict__", dict_entry.doc, dict_entry.pos) 4819 if self.in_pxd: 4820 scope.defined = 1 4821 else: 4822 scope.implemented = 1 4823 4824 if len(self.bases.args) > 1: 4825 if not has_body or self.in_pxd: 4826 error(self.bases.args[1].pos, "Only declare first base in declaration.") 4827 # At runtime, we check that the other bases are heap types 4828 # and that a __dict__ is added if required. 4829 for other_base in self.bases.args[1:]: 4830 if other_base.analyse_as_type(env): 4831 error(other_base.pos, "Only one extension type base class allowed.") 4832 self.entry.type.early_init = 0 4833 from . import ExprNodes 4834 self.type_init_args = ExprNodes.TupleNode( 4835 self.pos, 4836 args=[ExprNodes.IdentifierStringNode(self.pos, value=self.class_name), 4837 self.bases, 4838 ExprNodes.DictNode(self.pos, key_value_pairs=[])]) 4839 elif self.base_type: 4840 self.entry.type.early_init = self.base_type.is_external or self.base_type.early_init 4841 self.type_init_args = None 4842 else: 4843 self.entry.type.early_init = 1 4844 self.type_init_args = None 4845 4846 env.allocate_vtable_names(self.entry) 4847 4848 for thunk in self.entry.type.defered_declarations: 4849 thunk() 4850 4851 def analyse_expressions(self, env): 4852 if self.body: 4853 scope = self.entry.type.scope 4854 self.body = self.body.analyse_expressions(scope) 4855 if self.type_init_args: 4856 self.type_init_args.analyse_expressions(env) 4857 return self 4858 4859 def generate_function_definitions(self, env, code): 4860 if self.body: 4861 self.generate_lambda_definitions(self.scope, code) 4862 self.body.generate_function_definitions(self.scope, code) 4863 4864 def generate_execution_code(self, code): 4865 # This is needed to generate evaluation code for 4866 # default values of method arguments. 4867 code.mark_pos(self.pos) 4868 if self.body: 4869 self.body.generate_execution_code(code) 4870 if not self.entry.type.early_init: 4871 if self.type_init_args: 4872 self.type_init_args.generate_evaluation_code(code) 4873 bases = "PyTuple_GET_ITEM(%s, 1)" % self.type_init_args.result() 4874 first_base = "((PyTypeObject*)PyTuple_GET_ITEM(%s, 0))" % bases 4875 # Let Python do the base types compatibility checking. 4876 trial_type = code.funcstate.allocate_temp(PyrexTypes.py_object_type, True) 4877 code.putln("%s = PyType_Type.tp_new(&PyType_Type, %s, NULL);" % ( 4878 trial_type, self.type_init_args.result())) 4879 code.putln(code.error_goto_if_null(trial_type, self.pos)) 4880 code.put_gotref(trial_type) 4881 code.putln("if (((PyTypeObject*) %s)->tp_base != %s) {" % ( 4882 trial_type, first_base)) 4883 code.putln("PyErr_Format(PyExc_TypeError, \"best base '%s' must be equal to first base '%s'\",") 4884 code.putln(" ((PyTypeObject*) %s)->tp_base->tp_name, %s->tp_name);" % ( 4885 trial_type, first_base)) 4886 code.putln(code.error_goto(self.pos)) 4887 code.putln("}") 4888 code.funcstate.release_temp(trial_type) 4889 code.put_incref(bases, PyrexTypes.py_object_type) 4890 code.put_giveref(bases) 4891 code.putln("%s.tp_bases = %s;" % (self.entry.type.typeobj_cname, bases)) 4892 code.put_decref_clear(trial_type, PyrexTypes.py_object_type) 4893 self.type_init_args.generate_disposal_code(code) 4894 self.type_init_args.free_temps(code) 4895 4896 self.generate_type_ready_code(self.entry, code, True) 4897 4898 # Also called from ModuleNode for early init types. 4899 @staticmethod 4900 def generate_type_ready_code(entry, code, heap_type_bases=False): 4901 # Generate a call to PyType_Ready for an extension 4902 # type defined in this module. 4903 type = entry.type 4904 typeobj_cname = type.typeobj_cname 4905 scope = type.scope 4906 if not scope: # could be None if there was an error 4907 return 4908 if entry.visibility != 'extern': 4909 for slot in TypeSlots.slot_table: 4910 slot.generate_dynamic_init_code(scope, code) 4911 if heap_type_bases: 4912 code.globalstate.use_utility_code( 4913 UtilityCode.load_cached('PyType_Ready', 'ExtensionTypes.c')) 4914 readyfunc = "__Pyx_PyType_Ready" 4915 else: 4916 readyfunc = "PyType_Ready" 4917 code.putln( 4918 "if (%s(&%s) < 0) %s" % ( 4919 readyfunc, 4920 typeobj_cname, 4921 code.error_goto(entry.pos))) 4922 # Don't inherit tp_print from builtin types, restoring the 4923 # behavior of using tp_repr or tp_str instead. 4924 # ("tp_print" was renamed to "tp_vectorcall_offset" in Py3.8b1) 4925 code.putln("#if PY_VERSION_HEX < 0x030800B1") 4926 code.putln("%s.tp_print = 0;" % typeobj_cname) 4927 code.putln("#endif") 4928 4929 # Use specialised attribute lookup for types with generic lookup but no instance dict. 4930 getattr_slot_func = TypeSlots.get_slot_code_by_name(scope, 'tp_getattro') 4931 dictoffset_slot_func = TypeSlots.get_slot_code_by_name(scope, 'tp_dictoffset') 4932 if getattr_slot_func == '0' and dictoffset_slot_func == '0': 4933 if type.is_final_type: 4934 py_cfunc = "__Pyx_PyObject_GenericGetAttrNoDict" # grepable 4935 utility_func = "PyObject_GenericGetAttrNoDict" 4936 else: 4937 py_cfunc = "__Pyx_PyObject_GenericGetAttr" 4938 utility_func = "PyObject_GenericGetAttr" 4939 code.globalstate.use_utility_code(UtilityCode.load_cached(utility_func, "ObjectHandling.c")) 4940 4941 code.putln("if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) &&" 4942 " likely(!%s.tp_dictoffset && %s.tp_getattro == PyObject_GenericGetAttr)) {" % ( 4943 typeobj_cname, typeobj_cname)) 4944 code.putln("%s.tp_getattro = %s;" % ( 4945 typeobj_cname, py_cfunc)) 4946 code.putln("}") 4947 4948 # Fix special method docstrings. This is a bit of a hack, but 4949 # unless we let PyType_Ready create the slot wrappers we have 4950 # a significant performance hit. (See trac #561.) 4951 for func in entry.type.scope.pyfunc_entries: 4952 is_buffer = func.name in ('__getbuffer__', '__releasebuffer__') 4953 if (func.is_special and Options.docstrings and 4954 func.wrapperbase_cname and not is_buffer): 4955 slot = TypeSlots.method_name_to_slot.get(func.name) 4956 preprocessor_guard = slot.preprocessor_guard_code() if slot else None 4957 if preprocessor_guard: 4958 code.putln(preprocessor_guard) 4959 code.putln('#if CYTHON_COMPILING_IN_CPYTHON') 4960 code.putln("{") 4961 code.putln( 4962 'PyObject *wrapper = PyObject_GetAttrString((PyObject *)&%s, "%s"); %s' % ( 4963 typeobj_cname, 4964 func.name, 4965 code.error_goto_if_null('wrapper', entry.pos))) 4966 code.putln( 4967 "if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {") 4968 code.putln( 4969 "%s = *((PyWrapperDescrObject *)wrapper)->d_base;" % ( 4970 func.wrapperbase_cname)) 4971 code.putln( 4972 "%s.doc = %s;" % (func.wrapperbase_cname, func.doc_cname)) 4973 code.putln( 4974 "((PyWrapperDescrObject *)wrapper)->d_base = &%s;" % ( 4975 func.wrapperbase_cname)) 4976 code.putln("}") 4977 code.putln("}") 4978 code.putln('#endif') 4979 if preprocessor_guard: 4980 code.putln('#endif') 4981 if type.vtable_cname: 4982 code.globalstate.use_utility_code( 4983 UtilityCode.load_cached('SetVTable', 'ImportExport.c')) 4984 code.putln( 4985 "if (__Pyx_SetVtable(%s.tp_dict, %s) < 0) %s" % ( 4986 typeobj_cname, 4987 type.vtabptr_cname, 4988 code.error_goto(entry.pos))) 4989 if heap_type_bases: 4990 code.globalstate.use_utility_code( 4991 UtilityCode.load_cached('MergeVTables', 'ImportExport.c')) 4992 code.putln("if (__Pyx_MergeVtables(&%s) < 0) %s" % ( 4993 typeobj_cname, 4994 code.error_goto(entry.pos))) 4995 if not type.scope.is_internal and not type.scope.directives.get('internal'): 4996 # scope.is_internal is set for types defined by 4997 # Cython (such as closures), the 'internal' 4998 # directive is set by users 4999 code.putln( 5000 'if (PyObject_SetAttr(%s, %s, (PyObject *)&%s) < 0) %s' % ( 5001 Naming.module_cname, 5002 code.intern_identifier(scope.class_name), 5003 typeobj_cname, 5004 code.error_goto(entry.pos))) 5005 weakref_entry = scope.lookup_here("__weakref__") if not scope.is_closure_class_scope else None 5006 if weakref_entry: 5007 if weakref_entry.type is py_object_type: 5008 tp_weaklistoffset = "%s.tp_weaklistoffset" % typeobj_cname 5009 if type.typedef_flag: 5010 objstruct = type.objstruct_cname 5011 else: 5012 objstruct = "struct %s" % type.objstruct_cname 5013 code.putln("if (%s == 0) %s = offsetof(%s, %s);" % ( 5014 tp_weaklistoffset, 5015 tp_weaklistoffset, 5016 objstruct, 5017 weakref_entry.cname)) 5018 else: 5019 error(weakref_entry.pos, "__weakref__ slot must be of type 'object'") 5020 if scope.lookup_here("__reduce_cython__") if not scope.is_closure_class_scope else None: 5021 # Unfortunately, we cannot reliably detect whether a 5022 # superclass defined __reduce__ at compile time, so we must 5023 # do so at runtime. 5024 code.globalstate.use_utility_code( 5025 UtilityCode.load_cached('SetupReduce', 'ExtensionTypes.c')) 5026 code.putln('if (__Pyx_setup_reduce((PyObject*)&%s) < 0) %s' % ( 5027 typeobj_cname, 5028 code.error_goto(entry.pos))) 5029 # Generate code to initialise the typeptr of an extension 5030 # type defined in this module to point to its type object. 5031 if type.typeobj_cname: 5032 code.putln( 5033 "%s = &%s;" % ( 5034 type.typeptr_cname, type.typeobj_cname)) 5035 5036 def annotate(self, code): 5037 if self.type_init_args: 5038 self.type_init_args.annotate(code) 5039 if self.body: 5040 self.body.annotate(code) 5041 5042 5043class PropertyNode(StatNode): 5044 # Definition of a property in an extension type. 5045 # 5046 # name string 5047 # doc EncodedString or None Doc string 5048 # entry Symtab.Entry 5049 # body StatListNode 5050 5051 child_attrs = ["body"] 5052 5053 def analyse_declarations(self, env): 5054 self.entry = env.declare_property(self.name, self.doc, self.pos) 5055 self.entry.scope.directives = env.directives 5056 self.body.analyse_declarations(self.entry.scope) 5057 5058 def analyse_expressions(self, env): 5059 self.body = self.body.analyse_expressions(env) 5060 return self 5061 5062 def generate_function_definitions(self, env, code): 5063 self.body.generate_function_definitions(env, code) 5064 5065 def generate_execution_code(self, code): 5066 pass 5067 5068 def annotate(self, code): 5069 self.body.annotate(code) 5070 5071 5072class GlobalNode(StatNode): 5073 # Global variable declaration. 5074 # 5075 # names [string] 5076 5077 child_attrs = [] 5078 5079 def analyse_declarations(self, env): 5080 for name in self.names: 5081 env.declare_global(name, self.pos) 5082 5083 def analyse_expressions(self, env): 5084 return self 5085 5086 def generate_execution_code(self, code): 5087 pass 5088 5089 5090class NonlocalNode(StatNode): 5091 # Nonlocal variable declaration via the 'nonlocal' keyword. 5092 # 5093 # names [string] 5094 5095 child_attrs = [] 5096 5097 def analyse_declarations(self, env): 5098 for name in self.names: 5099 env.declare_nonlocal(name, self.pos) 5100 5101 def analyse_expressions(self, env): 5102 return self 5103 5104 def generate_execution_code(self, code): 5105 pass 5106 5107 5108class ExprStatNode(StatNode): 5109 # Expression used as a statement. 5110 # 5111 # expr ExprNode 5112 5113 child_attrs = ["expr"] 5114 5115 def analyse_declarations(self, env): 5116 from . import ExprNodes 5117 expr = self.expr 5118 if isinstance(expr, ExprNodes.GeneralCallNode): 5119 func = expr.function.as_cython_attribute() 5120 if func == u'declare': 5121 args, kwds = expr.explicit_args_kwds() 5122 if len(args): 5123 error(expr.pos, "Variable names must be specified.") 5124 for var, type_node in kwds.key_value_pairs: 5125 type = type_node.analyse_as_type(env) 5126 if type is None: 5127 error(type_node.pos, "Unknown type") 5128 else: 5129 env.declare_var(var.value, type, var.pos, is_cdef=True) 5130 self.__class__ = PassStatNode 5131 elif getattr(expr, 'annotation', None) is not None: 5132 if expr.is_name: 5133 # non-code variable annotation, e.g. "name: type" 5134 expr.declare_from_annotation(env) 5135 self.__class__ = PassStatNode 5136 elif expr.is_attribute or expr.is_subscript: 5137 # unused expression with annotation, e.g. "a[0]: type" or "a.xyz : type" 5138 self.__class__ = PassStatNode 5139 5140 def analyse_expressions(self, env): 5141 self.expr.result_is_used = False # hint that .result() may safely be left empty 5142 self.expr = self.expr.analyse_expressions(env) 5143 # Repeat in case of node replacement. 5144 self.expr.result_is_used = False # hint that .result() may safely be left empty 5145 return self 5146 5147 def nogil_check(self, env): 5148 if self.expr.type.is_pyobject and self.expr.is_temp: 5149 self.gil_error() 5150 5151 gil_message = "Discarding owned Python object" 5152 5153 def generate_execution_code(self, code): 5154 code.mark_pos(self.pos) 5155 self.expr.result_is_used = False # hint that .result() may safely be left empty 5156 self.expr.generate_evaluation_code(code) 5157 if not self.expr.is_temp and self.expr.result(): 5158 result = self.expr.result() 5159 if not self.expr.type.is_void: 5160 result = "(void)(%s)" % result 5161 code.putln("%s;" % result) 5162 self.expr.generate_disposal_code(code) 5163 self.expr.free_temps(code) 5164 5165 def generate_function_definitions(self, env, code): 5166 self.expr.generate_function_definitions(env, code) 5167 5168 def annotate(self, code): 5169 self.expr.annotate(code) 5170 5171 5172class AssignmentNode(StatNode): 5173 # Abstract base class for assignment nodes. 5174 # 5175 # The analyse_expressions and generate_execution_code 5176 # phases of assignments are split into two sub-phases 5177 # each, to enable all the right hand sides of a 5178 # parallel assignment to be evaluated before assigning 5179 # to any of the left hand sides. 5180 5181 def analyse_expressions(self, env): 5182 node = self.analyse_types(env) 5183 if isinstance(node, AssignmentNode) and not isinstance(node, ParallelAssignmentNode): 5184 if node.rhs.type.is_ptr and node.rhs.is_ephemeral(): 5185 error(self.pos, "Storing unsafe C derivative of temporary Python reference") 5186 return node 5187 5188# def analyse_expressions(self, env): 5189# self.analyse_expressions_1(env) 5190# self.analyse_expressions_2(env) 5191 5192 def generate_execution_code(self, code): 5193 code.mark_pos(self.pos) 5194 self.generate_rhs_evaluation_code(code) 5195 self.generate_assignment_code(code) 5196 5197 5198class SingleAssignmentNode(AssignmentNode): 5199 # The simplest case: 5200 # 5201 # a = b 5202 # 5203 # lhs ExprNode Left hand side 5204 # rhs ExprNode Right hand side 5205 # first bool Is this guaranteed the first assignment to lhs? 5206 # is_overloaded_assignment bool Is this assignment done via an overloaded operator= 5207 # exception_check 5208 # exception_value 5209 5210 child_attrs = ["lhs", "rhs"] 5211 first = False 5212 is_overloaded_assignment = False 5213 declaration_only = False 5214 5215 def analyse_declarations(self, env): 5216 from . import ExprNodes 5217 5218 # handle declarations of the form x = cython.foo() 5219 if isinstance(self.rhs, ExprNodes.CallNode): 5220 func_name = self.rhs.function.as_cython_attribute() 5221 if func_name: 5222 args, kwds = self.rhs.explicit_args_kwds() 5223 if func_name in ['declare', 'typedef']: 5224 if len(args) > 2: 5225 error(args[2].pos, "Invalid positional argument.") 5226 return 5227 if kwds is not None: 5228 kwdict = kwds.compile_time_value(None) 5229 if func_name == 'typedef' or 'visibility' not in kwdict: 5230 error(kwds.pos, "Invalid keyword argument.") 5231 return 5232 visibility = kwdict['visibility'] 5233 else: 5234 visibility = 'private' 5235 type = args[0].analyse_as_type(env) 5236 if type is None: 5237 error(args[0].pos, "Unknown type") 5238 return 5239 lhs = self.lhs 5240 if func_name == 'declare': 5241 if isinstance(lhs, ExprNodes.NameNode): 5242 vars = [(lhs.name, lhs.pos)] 5243 elif isinstance(lhs, ExprNodes.TupleNode): 5244 vars = [(var.name, var.pos) for var in lhs.args] 5245 else: 5246 error(lhs.pos, "Invalid declaration") 5247 return 5248 for var, pos in vars: 5249 env.declare_var(var, type, pos, is_cdef=True, visibility=visibility) 5250 if len(args) == 2: 5251 # we have a value 5252 self.rhs = args[1] 5253 else: 5254 self.declaration_only = True 5255 else: 5256 self.declaration_only = True 5257 if not isinstance(lhs, ExprNodes.NameNode): 5258 error(lhs.pos, "Invalid declaration.") 5259 env.declare_typedef(lhs.name, type, self.pos, visibility='private') 5260 5261 elif func_name in ['struct', 'union']: 5262 self.declaration_only = True 5263 if len(args) > 0 or kwds is None: 5264 error(self.rhs.pos, "Struct or union members must be given by name.") 5265 return 5266 members = [] 5267 for member, type_node in kwds.key_value_pairs: 5268 type = type_node.analyse_as_type(env) 5269 if type is None: 5270 error(type_node.pos, "Unknown type") 5271 else: 5272 members.append((member.value, type, member.pos)) 5273 if len(members) < len(kwds.key_value_pairs): 5274 return 5275 if not isinstance(self.lhs, ExprNodes.NameNode): 5276 error(self.lhs.pos, "Invalid declaration.") 5277 name = self.lhs.name 5278 scope = StructOrUnionScope(name) 5279 env.declare_struct_or_union(name, func_name, scope, False, self.rhs.pos) 5280 for member, type, pos in members: 5281 scope.declare_var(member, type, pos) 5282 5283 elif func_name == 'fused_type': 5284 # dtype = cython.fused_type(...) 5285 self.declaration_only = True 5286 if kwds: 5287 error(self.rhs.function.pos, 5288 "fused_type does not take keyword arguments") 5289 5290 fusednode = FusedTypeNode(self.rhs.pos, 5291 name=self.lhs.name, types=args) 5292 fusednode.analyse_declarations(env) 5293 5294 if self.declaration_only: 5295 return 5296 else: 5297 self.lhs.analyse_target_declaration(env) 5298 5299 def analyse_types(self, env, use_temp=0): 5300 from . import ExprNodes 5301 5302 self.rhs = self.rhs.analyse_types(env) 5303 5304 unrolled_assignment = self.unroll_rhs(env) 5305 if unrolled_assignment: 5306 return unrolled_assignment 5307 5308 self.lhs = self.lhs.analyse_target_types(env) 5309 self.lhs.gil_assignment_check(env) 5310 unrolled_assignment = self.unroll_lhs(env) 5311 if unrolled_assignment: 5312 return unrolled_assignment 5313 5314 if isinstance(self.lhs, ExprNodes.MemoryViewIndexNode): 5315 self.lhs.analyse_broadcast_operation(self.rhs) 5316 self.lhs = self.lhs.analyse_as_memview_scalar_assignment(self.rhs) 5317 elif self.lhs.type.is_array: 5318 if not isinstance(self.lhs, ExprNodes.SliceIndexNode): 5319 # cannot assign to C array, only to its full slice 5320 self.lhs = ExprNodes.SliceIndexNode(self.lhs.pos, base=self.lhs, start=None, stop=None) 5321 self.lhs = self.lhs.analyse_target_types(env) 5322 5323 if self.lhs.type.is_cpp_class: 5324 op = env.lookup_operator_for_types(self.pos, '=', [self.lhs.type, self.rhs.type]) 5325 if op: 5326 rhs = self.rhs 5327 self.is_overloaded_assignment = True 5328 self.exception_check = op.type.exception_check 5329 self.exception_value = op.type.exception_value 5330 if self.exception_check == '+' and self.exception_value is None: 5331 env.use_utility_code(UtilityCode.load_cached("CppExceptionConversion", "CppSupport.cpp")) 5332 else: 5333 rhs = self.rhs.coerce_to(self.lhs.type, env) 5334 else: 5335 rhs = self.rhs.coerce_to(self.lhs.type, env) 5336 5337 if use_temp or rhs.is_attribute or ( 5338 not rhs.is_name and not rhs.is_literal and 5339 rhs.type.is_pyobject): 5340 # things like (cdef) attribute access are not safe (traverses pointers) 5341 rhs = rhs.coerce_to_temp(env) 5342 elif rhs.type.is_pyobject: 5343 rhs = rhs.coerce_to_simple(env) 5344 self.rhs = rhs 5345 return self 5346 5347 def unroll(self, node, target_size, env): 5348 from . import ExprNodes, UtilNodes 5349 5350 base = node 5351 start_node = stop_node = step_node = check_node = None 5352 5353 if node.type.is_ctuple: 5354 slice_size = node.type.size 5355 5356 elif node.type.is_ptr or node.type.is_array: 5357 while isinstance(node, ExprNodes.SliceIndexNode) and not (node.start or node.stop): 5358 base = node = node.base 5359 if isinstance(node, ExprNodes.SliceIndexNode): 5360 base = node.base 5361 start_node = node.start 5362 if start_node: 5363 start_node = start_node.coerce_to(PyrexTypes.c_py_ssize_t_type, env) 5364 stop_node = node.stop 5365 if stop_node: 5366 stop_node = stop_node.coerce_to(PyrexTypes.c_py_ssize_t_type, env) 5367 else: 5368 if node.type.is_array and node.type.size: 5369 stop_node = ExprNodes.IntNode( 5370 self.pos, value=str(node.type.size), 5371 constant_result=(node.type.size if isinstance(node.type.size, _py_int_types) 5372 else ExprNodes.constant_value_not_set)) 5373 else: 5374 error(self.pos, "C array iteration requires known end index") 5375 return 5376 step_node = None #node.step 5377 if step_node: 5378 step_node = step_node.coerce_to(PyrexTypes.c_py_ssize_t_type, env) 5379 5380 # TODO: Factor out SliceIndexNode.generate_slice_guard_code() for use here. 5381 def get_const(node, none_value): 5382 if node is None: 5383 return none_value 5384 elif node.has_constant_result(): 5385 return node.constant_result 5386 else: 5387 raise ValueError("Not a constant.") 5388 5389 try: 5390 slice_size = (get_const(stop_node, None) - get_const(start_node, 0)) / get_const(step_node, 1) 5391 except ValueError: 5392 error(self.pos, "C array assignment currently requires known endpoints") 5393 return 5394 5395 elif node.type.is_array: 5396 slice_size = node.type.size 5397 if not isinstance(slice_size, _py_int_types): 5398 return # might still work when coercing to Python 5399 else: 5400 return 5401 5402 else: 5403 return 5404 5405 if slice_size != target_size: 5406 error(self.pos, "Assignment to/from slice of wrong length, expected %s, got %s" % ( 5407 slice_size, target_size)) 5408 return 5409 5410 items = [] 5411 base = UtilNodes.LetRefNode(base) 5412 refs = [base] 5413 if start_node and not start_node.is_literal: 5414 start_node = UtilNodes.LetRefNode(start_node) 5415 refs.append(start_node) 5416 if stop_node and not stop_node.is_literal: 5417 stop_node = UtilNodes.LetRefNode(stop_node) 5418 refs.append(stop_node) 5419 if step_node and not step_node.is_literal: 5420 step_node = UtilNodes.LetRefNode(step_node) 5421 refs.append(step_node) 5422 5423 for ix in range(target_size): 5424 ix_node = ExprNodes.IntNode(self.pos, value=str(ix), constant_result=ix, type=PyrexTypes.c_py_ssize_t_type) 5425 if step_node is not None: 5426 if step_node.has_constant_result(): 5427 step_value = ix_node.constant_result * step_node.constant_result 5428 ix_node = ExprNodes.IntNode(self.pos, value=str(step_value), constant_result=step_value) 5429 else: 5430 ix_node = ExprNodes.MulNode(self.pos, operator='*', operand1=step_node, operand2=ix_node) 5431 if start_node is not None: 5432 if start_node.has_constant_result() and ix_node.has_constant_result(): 5433 index_value = ix_node.constant_result + start_node.constant_result 5434 ix_node = ExprNodes.IntNode(self.pos, value=str(index_value), constant_result=index_value) 5435 else: 5436 ix_node = ExprNodes.AddNode( 5437 self.pos, operator='+', operand1=start_node, operand2=ix_node) 5438 items.append(ExprNodes.IndexNode(self.pos, base=base, index=ix_node.analyse_types(env))) 5439 return check_node, refs, items 5440 5441 def unroll_assignments(self, refs, check_node, lhs_list, rhs_list, env): 5442 from . import UtilNodes 5443 assignments = [] 5444 for lhs, rhs in zip(lhs_list, rhs_list): 5445 assignments.append(SingleAssignmentNode(self.pos, lhs=lhs, rhs=rhs, first=self.first)) 5446 node = ParallelAssignmentNode(pos=self.pos, stats=assignments).analyse_expressions(env) 5447 if check_node: 5448 node = StatListNode(pos=self.pos, stats=[check_node, node]) 5449 for ref in refs[::-1]: 5450 node = UtilNodes.LetNode(ref, node) 5451 return node 5452 5453 def unroll_rhs(self, env): 5454 from . import ExprNodes 5455 if not isinstance(self.lhs, ExprNodes.TupleNode): 5456 return 5457 if any(arg.is_starred for arg in self.lhs.args): 5458 return 5459 5460 unrolled = self.unroll(self.rhs, len(self.lhs.args), env) 5461 if not unrolled: 5462 return 5463 check_node, refs, rhs = unrolled 5464 return self.unroll_assignments(refs, check_node, self.lhs.args, rhs, env) 5465 5466 def unroll_lhs(self, env): 5467 if self.lhs.type.is_ctuple: 5468 # Handled directly. 5469 return 5470 from . import ExprNodes 5471 if not isinstance(self.rhs, ExprNodes.TupleNode): 5472 return 5473 5474 unrolled = self.unroll(self.lhs, len(self.rhs.args), env) 5475 if not unrolled: 5476 return 5477 check_node, refs, lhs = unrolled 5478 return self.unroll_assignments(refs, check_node, lhs, self.rhs.args, env) 5479 5480 def generate_rhs_evaluation_code(self, code): 5481 self.rhs.generate_evaluation_code(code) 5482 5483 def generate_assignment_code(self, code, overloaded_assignment=False): 5484 if self.is_overloaded_assignment: 5485 self.lhs.generate_assignment_code( 5486 self.rhs, 5487 code, 5488 overloaded_assignment=self.is_overloaded_assignment, 5489 exception_check=self.exception_check, 5490 exception_value=self.exception_value) 5491 else: 5492 self.lhs.generate_assignment_code(self.rhs, code) 5493 5494 def generate_function_definitions(self, env, code): 5495 self.rhs.generate_function_definitions(env, code) 5496 5497 def annotate(self, code): 5498 self.lhs.annotate(code) 5499 self.rhs.annotate(code) 5500 5501 5502class CascadedAssignmentNode(AssignmentNode): 5503 # An assignment with multiple left hand sides: 5504 # 5505 # a = b = c 5506 # 5507 # lhs_list [ExprNode] Left hand sides 5508 # rhs ExprNode Right hand sides 5509 # 5510 # Used internally: 5511 # 5512 # coerced_values [ExprNode] RHS coerced to all distinct LHS types 5513 # cloned_values [ExprNode] cloned RHS value for each LHS 5514 # assignment_overloads [Bool] If each assignment uses a C++ operator= 5515 5516 child_attrs = ["lhs_list", "rhs", "coerced_values", "cloned_values"] 5517 cloned_values = None 5518 coerced_values = None 5519 assignment_overloads = None 5520 5521 def analyse_declarations(self, env): 5522 for lhs in self.lhs_list: 5523 lhs.analyse_target_declaration(env) 5524 5525 def analyse_types(self, env, use_temp=0): 5526 from .ExprNodes import CloneNode, ProxyNode 5527 5528 # collect distinct types used on the LHS 5529 lhs_types = set() 5530 for i, lhs in enumerate(self.lhs_list): 5531 lhs = self.lhs_list[i] = lhs.analyse_target_types(env) 5532 lhs.gil_assignment_check(env) 5533 lhs_types.add(lhs.type) 5534 5535 rhs = self.rhs.analyse_types(env) 5536 # common special case: only one type needed on the LHS => coerce only once 5537 if len(lhs_types) == 1: 5538 # Avoid coercion for overloaded assignment operators. 5539 if next(iter(lhs_types)).is_cpp_class: 5540 op = env.lookup_operator('=', [lhs, self.rhs]) 5541 if not op: 5542 rhs = rhs.coerce_to(lhs_types.pop(), env) 5543 else: 5544 rhs = rhs.coerce_to(lhs_types.pop(), env) 5545 5546 if not rhs.is_name and not rhs.is_literal and ( 5547 use_temp or rhs.is_attribute or rhs.type.is_pyobject): 5548 rhs = rhs.coerce_to_temp(env) 5549 else: 5550 rhs = rhs.coerce_to_simple(env) 5551 self.rhs = ProxyNode(rhs) if rhs.is_temp else rhs 5552 5553 # clone RHS and coerce it to all distinct LHS types 5554 self.coerced_values = [] 5555 coerced_values = {} 5556 self.assignment_overloads = [] 5557 for lhs in self.lhs_list: 5558 overloaded = lhs.type.is_cpp_class and env.lookup_operator('=', [lhs, self.rhs]) 5559 self.assignment_overloads.append(overloaded) 5560 if lhs.type not in coerced_values and lhs.type != rhs.type: 5561 rhs = CloneNode(self.rhs) 5562 if not overloaded: 5563 rhs = rhs.coerce_to(lhs.type, env) 5564 self.coerced_values.append(rhs) 5565 coerced_values[lhs.type] = rhs 5566 5567 # clone coerced values for all LHS assignments 5568 self.cloned_values = [] 5569 for lhs in self.lhs_list: 5570 rhs = coerced_values.get(lhs.type, self.rhs) 5571 self.cloned_values.append(CloneNode(rhs)) 5572 return self 5573 5574 def generate_rhs_evaluation_code(self, code): 5575 self.rhs.generate_evaluation_code(code) 5576 5577 def generate_assignment_code(self, code, overloaded_assignment=False): 5578 # prepare all coercions 5579 for rhs in self.coerced_values: 5580 rhs.generate_evaluation_code(code) 5581 # assign clones to LHS 5582 for lhs, rhs, overload in zip(self.lhs_list, self.cloned_values, self.assignment_overloads): 5583 rhs.generate_evaluation_code(code) 5584 lhs.generate_assignment_code(rhs, code, overloaded_assignment=overload) 5585 # dispose of coerced values and original RHS 5586 for rhs_value in self.coerced_values: 5587 rhs_value.generate_disposal_code(code) 5588 rhs_value.free_temps(code) 5589 self.rhs.generate_disposal_code(code) 5590 self.rhs.free_temps(code) 5591 5592 def generate_function_definitions(self, env, code): 5593 self.rhs.generate_function_definitions(env, code) 5594 5595 def annotate(self, code): 5596 for rhs in self.coerced_values: 5597 rhs.annotate(code) 5598 for lhs, rhs in zip(self.lhs_list, self.cloned_values): 5599 lhs.annotate(code) 5600 rhs.annotate(code) 5601 self.rhs.annotate(code) 5602 5603 5604class ParallelAssignmentNode(AssignmentNode): 5605 # A combined packing/unpacking assignment: 5606 # 5607 # a, b, c = d, e, f 5608 # 5609 # This has been rearranged by the parser into 5610 # 5611 # a = d ; b = e ; c = f 5612 # 5613 # but we must evaluate all the right hand sides 5614 # before assigning to any of the left hand sides. 5615 # 5616 # stats [AssignmentNode] The constituent assignments 5617 5618 child_attrs = ["stats"] 5619 5620 def analyse_declarations(self, env): 5621 for stat in self.stats: 5622 stat.analyse_declarations(env) 5623 5624 def analyse_expressions(self, env): 5625 self.stats = [stat.analyse_types(env, use_temp=1) 5626 for stat in self.stats] 5627 return self 5628 5629# def analyse_expressions(self, env): 5630# for stat in self.stats: 5631# stat.analyse_expressions_1(env, use_temp=1) 5632# for stat in self.stats: 5633# stat.analyse_expressions_2(env) 5634 5635 def generate_execution_code(self, code): 5636 code.mark_pos(self.pos) 5637 for stat in self.stats: 5638 stat.generate_rhs_evaluation_code(code) 5639 for stat in self.stats: 5640 stat.generate_assignment_code(code) 5641 5642 def generate_function_definitions(self, env, code): 5643 for stat in self.stats: 5644 stat.generate_function_definitions(env, code) 5645 5646 def annotate(self, code): 5647 for stat in self.stats: 5648 stat.annotate(code) 5649 5650 5651class InPlaceAssignmentNode(AssignmentNode): 5652 # An in place arithmetic operand: 5653 # 5654 # a += b 5655 # a -= b 5656 # ... 5657 # 5658 # lhs ExprNode Left hand side 5659 # rhs ExprNode Right hand side 5660 # operator char one of "+-*/%^&|" 5661 # 5662 # This code is a bit tricky because in order to obey Python 5663 # semantics the sub-expressions (e.g. indices) of the lhs must 5664 # not be evaluated twice. So we must re-use the values calculated 5665 # in evaluation phase for the assignment phase as well. 5666 # Fortunately, the type of the lhs node is fairly constrained 5667 # (it must be a NameNode, AttributeNode, or IndexNode). 5668 5669 child_attrs = ["lhs", "rhs"] 5670 5671 def analyse_declarations(self, env): 5672 self.lhs.analyse_target_declaration(env) 5673 5674 def analyse_types(self, env): 5675 self.rhs = self.rhs.analyse_types(env) 5676 self.lhs = self.lhs.analyse_target_types(env) 5677 5678 # When assigning to a fully indexed buffer or memoryview, coerce the rhs 5679 if self.lhs.is_memview_index or self.lhs.is_buffer_access: 5680 self.rhs = self.rhs.coerce_to(self.lhs.type, env) 5681 elif self.lhs.type.is_string and self.operator in '+-': 5682 # use pointer arithmetic for char* LHS instead of string concat 5683 self.rhs = self.rhs.coerce_to(PyrexTypes.c_py_ssize_t_type, env) 5684 return self 5685 5686 def generate_execution_code(self, code): 5687 code.mark_pos(self.pos) 5688 lhs, rhs = self.lhs, self.rhs 5689 rhs.generate_evaluation_code(code) 5690 lhs.generate_subexpr_evaluation_code(code) 5691 c_op = self.operator 5692 if c_op == "//": 5693 c_op = "/" 5694 elif c_op == "**": 5695 error(self.pos, "No C inplace power operator") 5696 if lhs.is_buffer_access or lhs.is_memview_index: 5697 if lhs.type.is_pyobject: 5698 error(self.pos, "In-place operators not allowed on object buffers in this release.") 5699 if c_op in ('/', '%') and lhs.type.is_int and not code.globalstate.directives['cdivision']: 5700 error(self.pos, "In-place non-c divide operators not allowed on int buffers.") 5701 lhs.generate_buffer_setitem_code(rhs, code, c_op) 5702 elif lhs.is_memview_slice: 5703 error(self.pos, "Inplace operators not supported on memoryview slices") 5704 else: 5705 # C++ 5706 # TODO: make sure overload is declared 5707 code.putln("%s %s= %s;" % (lhs.result(), c_op, rhs.result())) 5708 lhs.generate_subexpr_disposal_code(code) 5709 lhs.free_subexpr_temps(code) 5710 rhs.generate_disposal_code(code) 5711 rhs.free_temps(code) 5712 5713 def annotate(self, code): 5714 self.lhs.annotate(code) 5715 self.rhs.annotate(code) 5716 5717 def create_binop_node(self): 5718 from . import ExprNodes 5719 return ExprNodes.binop_node(self.pos, self.operator, self.lhs, self.rhs) 5720 5721 5722class PrintStatNode(StatNode): 5723 # print statement 5724 # 5725 # arg_tuple TupleNode 5726 # stream ExprNode or None (stdout) 5727 # append_newline boolean 5728 5729 child_attrs = ["arg_tuple", "stream"] 5730 5731 def analyse_expressions(self, env): 5732 if self.stream: 5733 stream = self.stream.analyse_expressions(env) 5734 self.stream = stream.coerce_to_pyobject(env) 5735 arg_tuple = self.arg_tuple.analyse_expressions(env) 5736 self.arg_tuple = arg_tuple.coerce_to_pyobject(env) 5737 env.use_utility_code(printing_utility_code) 5738 if len(self.arg_tuple.args) == 1 and self.append_newline: 5739 env.use_utility_code(printing_one_utility_code) 5740 return self 5741 5742 nogil_check = Node.gil_error 5743 gil_message = "Python print statement" 5744 5745 def generate_execution_code(self, code): 5746 code.mark_pos(self.pos) 5747 if self.stream: 5748 self.stream.generate_evaluation_code(code) 5749 stream_result = self.stream.py_result() 5750 else: 5751 stream_result = '0' 5752 if len(self.arg_tuple.args) == 1 and self.append_newline: 5753 arg = self.arg_tuple.args[0] 5754 arg.generate_evaluation_code(code) 5755 5756 code.putln( 5757 "if (__Pyx_PrintOne(%s, %s) < 0) %s" % ( 5758 stream_result, 5759 arg.py_result(), 5760 code.error_goto(self.pos))) 5761 arg.generate_disposal_code(code) 5762 arg.free_temps(code) 5763 else: 5764 self.arg_tuple.generate_evaluation_code(code) 5765 code.putln( 5766 "if (__Pyx_Print(%s, %s, %d) < 0) %s" % ( 5767 stream_result, 5768 self.arg_tuple.py_result(), 5769 self.append_newline, 5770 code.error_goto(self.pos))) 5771 self.arg_tuple.generate_disposal_code(code) 5772 self.arg_tuple.free_temps(code) 5773 5774 if self.stream: 5775 self.stream.generate_disposal_code(code) 5776 self.stream.free_temps(code) 5777 5778 def generate_function_definitions(self, env, code): 5779 if self.stream: 5780 self.stream.generate_function_definitions(env, code) 5781 self.arg_tuple.generate_function_definitions(env, code) 5782 5783 def annotate(self, code): 5784 if self.stream: 5785 self.stream.annotate(code) 5786 self.arg_tuple.annotate(code) 5787 5788 5789class ExecStatNode(StatNode): 5790 # exec statement 5791 # 5792 # args [ExprNode] 5793 5794 child_attrs = ["args"] 5795 5796 def analyse_expressions(self, env): 5797 for i, arg in enumerate(self.args): 5798 arg = arg.analyse_expressions(env) 5799 arg = arg.coerce_to_pyobject(env) 5800 self.args[i] = arg 5801 env.use_utility_code(Builtin.pyexec_utility_code) 5802 return self 5803 5804 nogil_check = Node.gil_error 5805 gil_message = "Python exec statement" 5806 5807 def generate_execution_code(self, code): 5808 code.mark_pos(self.pos) 5809 args = [] 5810 for arg in self.args: 5811 arg.generate_evaluation_code(code) 5812 args.append(arg.py_result()) 5813 args = tuple(args + ['0', '0'][:3-len(args)]) 5814 temp_result = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True) 5815 code.putln("%s = __Pyx_PyExec3(%s, %s, %s);" % ((temp_result,) + args)) 5816 for arg in self.args: 5817 arg.generate_disposal_code(code) 5818 arg.free_temps(code) 5819 code.putln( 5820 code.error_goto_if_null(temp_result, self.pos)) 5821 code.put_gotref(temp_result) 5822 code.put_decref_clear(temp_result, py_object_type) 5823 code.funcstate.release_temp(temp_result) 5824 5825 def annotate(self, code): 5826 for arg in self.args: 5827 arg.annotate(code) 5828 5829 5830class DelStatNode(StatNode): 5831 # del statement 5832 # 5833 # args [ExprNode] 5834 5835 child_attrs = ["args"] 5836 ignore_nonexisting = False 5837 5838 def analyse_declarations(self, env): 5839 for arg in self.args: 5840 arg.analyse_target_declaration(env) 5841 5842 def analyse_expressions(self, env): 5843 for i, arg in enumerate(self.args): 5844 arg = self.args[i] = arg.analyse_target_expression(env, None) 5845 if arg.type.is_pyobject or (arg.is_name and arg.type.is_memoryviewslice): 5846 if arg.is_name and arg.entry.is_cglobal: 5847 error(arg.pos, "Deletion of global C variable") 5848 elif arg.type.is_ptr and arg.type.base_type.is_cpp_class: 5849 self.cpp_check(env) 5850 elif arg.type.is_cpp_class: 5851 error(arg.pos, "Deletion of non-heap C++ object") 5852 elif arg.is_subscript and arg.base.type is Builtin.bytearray_type: 5853 pass # del ba[i] 5854 else: 5855 error(arg.pos, "Deletion of non-Python, non-C++ object") 5856 #arg.release_target_temp(env) 5857 return self 5858 5859 def nogil_check(self, env): 5860 for arg in self.args: 5861 if arg.type.is_pyobject: 5862 self.gil_error() 5863 5864 gil_message = "Deleting Python object" 5865 5866 def generate_execution_code(self, code): 5867 code.mark_pos(self.pos) 5868 for arg in self.args: 5869 if (arg.type.is_pyobject or 5870 arg.type.is_memoryviewslice or 5871 arg.is_subscript and arg.base.type is Builtin.bytearray_type): 5872 arg.generate_deletion_code( 5873 code, ignore_nonexisting=self.ignore_nonexisting) 5874 elif arg.type.is_ptr and arg.type.base_type.is_cpp_class: 5875 arg.generate_evaluation_code(code) 5876 code.putln("delete %s;" % arg.result()) 5877 arg.generate_disposal_code(code) 5878 arg.free_temps(code) 5879 # else error reported earlier 5880 5881 def annotate(self, code): 5882 for arg in self.args: 5883 arg.annotate(code) 5884 5885 5886class PassStatNode(StatNode): 5887 # pass statement 5888 5889 child_attrs = [] 5890 5891 def analyse_expressions(self, env): 5892 return self 5893 5894 def generate_execution_code(self, code): 5895 pass 5896 5897 5898class IndirectionNode(StatListNode): 5899 """ 5900 This adds an indirection so that the node can be shared and a subtree can 5901 be removed at any time by clearing self.stats. 5902 """ 5903 5904 def __init__(self, stats): 5905 super(IndirectionNode, self).__init__(stats[0].pos, stats=stats) 5906 5907 5908class BreakStatNode(StatNode): 5909 5910 child_attrs = [] 5911 is_terminator = True 5912 5913 def analyse_expressions(self, env): 5914 return self 5915 5916 def generate_execution_code(self, code): 5917 code.mark_pos(self.pos) 5918 if not code.break_label: 5919 error(self.pos, "break statement not inside loop") 5920 else: 5921 code.put_goto(code.break_label) 5922 5923 5924class ContinueStatNode(StatNode): 5925 5926 child_attrs = [] 5927 is_terminator = True 5928 5929 def analyse_expressions(self, env): 5930 return self 5931 5932 def generate_execution_code(self, code): 5933 if not code.continue_label: 5934 error(self.pos, "continue statement not inside loop") 5935 return 5936 code.mark_pos(self.pos) 5937 code.put_goto(code.continue_label) 5938 5939 5940class ReturnStatNode(StatNode): 5941 # return statement 5942 # 5943 # value ExprNode or None 5944 # return_type PyrexType 5945 # in_generator return inside of generator => raise StopIteration 5946 # in_async_gen return inside of async generator 5947 5948 child_attrs = ["value"] 5949 is_terminator = True 5950 in_generator = False 5951 in_async_gen = False 5952 5953 # Whether we are in a parallel section 5954 in_parallel = False 5955 5956 def analyse_expressions(self, env): 5957 return_type = env.return_type 5958 self.return_type = return_type 5959 if not return_type: 5960 error(self.pos, "Return not inside a function body") 5961 return self 5962 if self.value: 5963 if self.in_async_gen: 5964 error(self.pos, "Return with value in async generator") 5965 self.value = self.value.analyse_types(env) 5966 if return_type.is_void or return_type.is_returncode: 5967 error(self.value.pos, "Return with value in void function") 5968 else: 5969 self.value = self.value.coerce_to(env.return_type, env) 5970 else: 5971 if (not return_type.is_void 5972 and not return_type.is_pyobject 5973 and not return_type.is_returncode): 5974 error(self.pos, "Return value required") 5975 return self 5976 5977 def nogil_check(self, env): 5978 if self.return_type.is_pyobject: 5979 self.gil_error() 5980 5981 gil_message = "Returning Python object" 5982 5983 def generate_execution_code(self, code): 5984 code.mark_pos(self.pos) 5985 if not self.return_type: 5986 # error reported earlier 5987 return 5988 5989 value = self.value 5990 if self.return_type.is_pyobject: 5991 code.put_xdecref(Naming.retval_cname, self.return_type) 5992 if value and value.is_none: 5993 # Use specialised default handling for "return None". 5994 value = None 5995 5996 if value: 5997 value.generate_evaluation_code(code) 5998 if self.return_type.is_memoryviewslice: 5999 from . import MemoryView 6000 MemoryView.put_acquire_memoryviewslice( 6001 lhs_cname=Naming.retval_cname, 6002 lhs_type=self.return_type, 6003 lhs_pos=value.pos, 6004 rhs=value, 6005 code=code, 6006 have_gil=self.in_nogil_context) 6007 value.generate_post_assignment_code(code) 6008 elif self.in_generator: 6009 # return value == raise StopIteration(value), but uncatchable 6010 code.globalstate.use_utility_code( 6011 UtilityCode.load_cached("ReturnWithStopIteration", "Coroutine.c")) 6012 code.putln("%s = NULL; __Pyx_ReturnWithStopIteration(%s);" % ( 6013 Naming.retval_cname, 6014 value.py_result())) 6015 value.generate_disposal_code(code) 6016 else: 6017 value.make_owned_reference(code) 6018 code.putln("%s = %s;" % ( 6019 Naming.retval_cname, 6020 value.result_as(self.return_type))) 6021 value.generate_post_assignment_code(code) 6022 value.free_temps(code) 6023 else: 6024 if self.return_type.is_pyobject: 6025 if self.in_generator: 6026 if self.in_async_gen: 6027 code.globalstate.use_utility_code( 6028 UtilityCode.load_cached("StopAsyncIteration", "Coroutine.c")) 6029 code.put("PyErr_SetNone(__Pyx_PyExc_StopAsyncIteration); ") 6030 code.putln("%s = NULL;" % Naming.retval_cname) 6031 else: 6032 code.put_init_to_py_none(Naming.retval_cname, self.return_type) 6033 elif self.return_type.is_returncode: 6034 self.put_return(code, self.return_type.default_value) 6035 6036 for cname, type in code.funcstate.temps_holding_reference(): 6037 code.put_decref_clear(cname, type) 6038 6039 code.put_goto(code.return_label) 6040 6041 def put_return(self, code, value): 6042 if self.in_parallel: 6043 code.putln_openmp("#pragma omp critical(__pyx_returning)") 6044 code.putln("%s = %s;" % (Naming.retval_cname, value)) 6045 6046 def generate_function_definitions(self, env, code): 6047 if self.value is not None: 6048 self.value.generate_function_definitions(env, code) 6049 6050 def annotate(self, code): 6051 if self.value: 6052 self.value.annotate(code) 6053 6054 6055class RaiseStatNode(StatNode): 6056 # raise statement 6057 # 6058 # exc_type ExprNode or None 6059 # exc_value ExprNode or None 6060 # exc_tb ExprNode or None 6061 # cause ExprNode or None 6062 6063 child_attrs = ["exc_type", "exc_value", "exc_tb", "cause"] 6064 is_terminator = True 6065 6066 def analyse_expressions(self, env): 6067 if self.exc_type: 6068 exc_type = self.exc_type.analyse_types(env) 6069 self.exc_type = exc_type.coerce_to_pyobject(env) 6070 if self.exc_value: 6071 exc_value = self.exc_value.analyse_types(env) 6072 self.exc_value = exc_value.coerce_to_pyobject(env) 6073 if self.exc_tb: 6074 exc_tb = self.exc_tb.analyse_types(env) 6075 self.exc_tb = exc_tb.coerce_to_pyobject(env) 6076 if self.cause: 6077 cause = self.cause.analyse_types(env) 6078 self.cause = cause.coerce_to_pyobject(env) 6079 # special cases for builtin exceptions 6080 self.builtin_exc_name = None 6081 if self.exc_type and not self.exc_value and not self.exc_tb: 6082 exc = self.exc_type 6083 from . import ExprNodes 6084 if (isinstance(exc, ExprNodes.SimpleCallNode) and 6085 not (exc.args or (exc.arg_tuple is not None and exc.arg_tuple.args))): 6086 exc = exc.function # extract the exception type 6087 if exc.is_name and exc.entry.is_builtin: 6088 self.builtin_exc_name = exc.name 6089 if self.builtin_exc_name == 'MemoryError': 6090 self.exc_type = None # has a separate implementation 6091 return self 6092 6093 nogil_check = Node.gil_error 6094 gil_message = "Raising exception" 6095 6096 def generate_execution_code(self, code): 6097 code.mark_pos(self.pos) 6098 if self.builtin_exc_name == 'MemoryError': 6099 code.putln('PyErr_NoMemory(); %s' % code.error_goto(self.pos)) 6100 return 6101 6102 if self.exc_type: 6103 self.exc_type.generate_evaluation_code(code) 6104 type_code = self.exc_type.py_result() 6105 if self.exc_type.is_name: 6106 code.globalstate.use_entry_utility_code(self.exc_type.entry) 6107 else: 6108 type_code = "0" 6109 if self.exc_value: 6110 self.exc_value.generate_evaluation_code(code) 6111 value_code = self.exc_value.py_result() 6112 else: 6113 value_code = "0" 6114 if self.exc_tb: 6115 self.exc_tb.generate_evaluation_code(code) 6116 tb_code = self.exc_tb.py_result() 6117 else: 6118 tb_code = "0" 6119 if self.cause: 6120 self.cause.generate_evaluation_code(code) 6121 cause_code = self.cause.py_result() 6122 else: 6123 cause_code = "0" 6124 code.globalstate.use_utility_code(raise_utility_code) 6125 code.putln( 6126 "__Pyx_Raise(%s, %s, %s, %s);" % ( 6127 type_code, 6128 value_code, 6129 tb_code, 6130 cause_code)) 6131 for obj in (self.exc_type, self.exc_value, self.exc_tb, self.cause): 6132 if obj: 6133 obj.generate_disposal_code(code) 6134 obj.free_temps(code) 6135 code.putln( 6136 code.error_goto(self.pos)) 6137 6138 def generate_function_definitions(self, env, code): 6139 if self.exc_type is not None: 6140 self.exc_type.generate_function_definitions(env, code) 6141 if self.exc_value is not None: 6142 self.exc_value.generate_function_definitions(env, code) 6143 if self.exc_tb is not None: 6144 self.exc_tb.generate_function_definitions(env, code) 6145 if self.cause is not None: 6146 self.cause.generate_function_definitions(env, code) 6147 6148 def annotate(self, code): 6149 if self.exc_type: 6150 self.exc_type.annotate(code) 6151 if self.exc_value: 6152 self.exc_value.annotate(code) 6153 if self.exc_tb: 6154 self.exc_tb.annotate(code) 6155 if self.cause: 6156 self.cause.annotate(code) 6157 6158 6159class ReraiseStatNode(StatNode): 6160 6161 child_attrs = [] 6162 is_terminator = True 6163 6164 def analyse_expressions(self, env): 6165 return self 6166 6167 nogil_check = Node.gil_error 6168 gil_message = "Raising exception" 6169 6170 def generate_execution_code(self, code): 6171 code.mark_pos(self.pos) 6172 vars = code.funcstate.exc_vars 6173 if vars: 6174 code.globalstate.use_utility_code(restore_exception_utility_code) 6175 code.put_giveref(vars[0]) 6176 code.put_giveref(vars[1]) 6177 # fresh exceptions may not have a traceback yet (-> finally!) 6178 code.put_xgiveref(vars[2]) 6179 code.putln("__Pyx_ErrRestoreWithState(%s, %s, %s);" % tuple(vars)) 6180 for varname in vars: 6181 code.put("%s = 0; " % varname) 6182 code.putln() 6183 code.putln(code.error_goto(self.pos)) 6184 else: 6185 code.globalstate.use_utility_code( 6186 UtilityCode.load_cached("ReRaiseException", "Exceptions.c")) 6187 code.putln("__Pyx_ReraiseException(); %s" % code.error_goto(self.pos)) 6188 6189class AssertStatNode(StatNode): 6190 # assert statement 6191 # 6192 # cond ExprNode 6193 # value ExprNode or None 6194 6195 child_attrs = ["cond", "value"] 6196 6197 def analyse_expressions(self, env): 6198 self.cond = self.cond.analyse_boolean_expression(env) 6199 if self.value: 6200 value = self.value.analyse_types(env) 6201 if value.type is Builtin.tuple_type or not value.type.is_builtin_type: 6202 # prevent tuple values from being interpreted as argument value tuples 6203 from .ExprNodes import TupleNode 6204 value = TupleNode(value.pos, args=[value], slow=True) 6205 self.value = value.analyse_types(env, skip_children=True).coerce_to_pyobject(env) 6206 else: 6207 self.value = value.coerce_to_pyobject(env) 6208 return self 6209 6210 nogil_check = Node.gil_error 6211 gil_message = "Raising exception" 6212 6213 def generate_execution_code(self, code): 6214 code.putln("#ifndef CYTHON_WITHOUT_ASSERTIONS") 6215 code.putln("if (unlikely(!Py_OptimizeFlag)) {") 6216 code.mark_pos(self.pos) 6217 self.cond.generate_evaluation_code(code) 6218 code.putln( 6219 "if (unlikely(!%s)) {" % self.cond.result()) 6220 if self.value: 6221 self.value.generate_evaluation_code(code) 6222 code.putln( 6223 "PyErr_SetObject(PyExc_AssertionError, %s);" % self.value.py_result()) 6224 self.value.generate_disposal_code(code) 6225 self.value.free_temps(code) 6226 else: 6227 code.putln( 6228 "PyErr_SetNone(PyExc_AssertionError);") 6229 code.putln( 6230 code.error_goto(self.pos)) 6231 code.putln( 6232 "}") 6233 self.cond.generate_disposal_code(code) 6234 self.cond.free_temps(code) 6235 code.putln( 6236 "}") 6237 code.putln("#endif") 6238 6239 def generate_function_definitions(self, env, code): 6240 self.cond.generate_function_definitions(env, code) 6241 if self.value is not None: 6242 self.value.generate_function_definitions(env, code) 6243 6244 def annotate(self, code): 6245 self.cond.annotate(code) 6246 if self.value: 6247 self.value.annotate(code) 6248 6249 6250class IfStatNode(StatNode): 6251 # if statement 6252 # 6253 # if_clauses [IfClauseNode] 6254 # else_clause StatNode or None 6255 6256 child_attrs = ["if_clauses", "else_clause"] 6257 6258 def analyse_declarations(self, env): 6259 for if_clause in self.if_clauses: 6260 if_clause.analyse_declarations(env) 6261 if self.else_clause: 6262 self.else_clause.analyse_declarations(env) 6263 6264 def analyse_expressions(self, env): 6265 self.if_clauses = [if_clause.analyse_expressions(env) for if_clause in self.if_clauses] 6266 if self.else_clause: 6267 self.else_clause = self.else_clause.analyse_expressions(env) 6268 return self 6269 6270 def generate_execution_code(self, code): 6271 code.mark_pos(self.pos) 6272 end_label = code.new_label() 6273 last = len(self.if_clauses) 6274 if self.else_clause: 6275 # If the 'else' clause is 'unlikely', then set the preceding 'if' clause to 'likely' to reflect that. 6276 self._set_branch_hint(self.if_clauses[-1], self.else_clause, inverse=True) 6277 else: 6278 last -= 1 # avoid redundant goto at end of last if-clause 6279 for i, if_clause in enumerate(self.if_clauses): 6280 self._set_branch_hint(if_clause, if_clause.body) 6281 if_clause.generate_execution_code(code, end_label, is_last=i == last) 6282 if self.else_clause: 6283 code.mark_pos(self.else_clause.pos) 6284 code.putln("/*else*/ {") 6285 self.else_clause.generate_execution_code(code) 6286 code.putln("}") 6287 code.put_label(end_label) 6288 6289 def _set_branch_hint(self, clause, statements_node, inverse=False): 6290 if not statements_node.is_terminator: 6291 return 6292 if not isinstance(statements_node, StatListNode) or not statements_node.stats: 6293 return 6294 # Anything that unconditionally raises exceptions should be considered unlikely. 6295 if isinstance(statements_node.stats[-1], (RaiseStatNode, ReraiseStatNode)): 6296 if len(statements_node.stats) > 1: 6297 # Allow simple statements before the 'raise', but no conditions, loops, etc. 6298 non_branch_nodes = (ExprStatNode, AssignmentNode, DelStatNode, GlobalNode, NonlocalNode) 6299 for node in statements_node.stats[:-1]: 6300 if not isinstance(node, non_branch_nodes): 6301 return 6302 clause.branch_hint = 'likely' if inverse else 'unlikely' 6303 6304 def generate_function_definitions(self, env, code): 6305 for clause in self.if_clauses: 6306 clause.generate_function_definitions(env, code) 6307 if self.else_clause is not None: 6308 self.else_clause.generate_function_definitions(env, code) 6309 6310 def annotate(self, code): 6311 for if_clause in self.if_clauses: 6312 if_clause.annotate(code) 6313 if self.else_clause: 6314 self.else_clause.annotate(code) 6315 6316 6317class IfClauseNode(Node): 6318 # if or elif clause in an if statement 6319 # 6320 # condition ExprNode 6321 # body StatNode 6322 6323 child_attrs = ["condition", "body"] 6324 branch_hint = None 6325 6326 def analyse_declarations(self, env): 6327 self.body.analyse_declarations(env) 6328 6329 def analyse_expressions(self, env): 6330 self.condition = self.condition.analyse_temp_boolean_expression(env) 6331 self.body = self.body.analyse_expressions(env) 6332 return self 6333 6334 def generate_execution_code(self, code, end_label, is_last): 6335 self.condition.generate_evaluation_code(code) 6336 code.mark_pos(self.pos) 6337 condition = self.condition.result() 6338 if self.branch_hint: 6339 condition = '%s(%s)' % (self.branch_hint, condition) 6340 code.putln("if (%s) {" % condition) 6341 self.condition.generate_disposal_code(code) 6342 self.condition.free_temps(code) 6343 self.body.generate_execution_code(code) 6344 code.mark_pos(self.pos, trace=False) 6345 if not (is_last or self.body.is_terminator): 6346 code.put_goto(end_label) 6347 code.putln("}") 6348 6349 def generate_function_definitions(self, env, code): 6350 self.condition.generate_function_definitions(env, code) 6351 self.body.generate_function_definitions(env, code) 6352 6353 def annotate(self, code): 6354 self.condition.annotate(code) 6355 self.body.annotate(code) 6356 6357 6358class SwitchCaseNode(StatNode): 6359 # Generated in the optimization of an if-elif-else node 6360 # 6361 # conditions [ExprNode] 6362 # body StatNode 6363 6364 child_attrs = ['conditions', 'body'] 6365 6366 def generate_condition_evaluation_code(self, code): 6367 for cond in self.conditions: 6368 cond.generate_evaluation_code(code) 6369 6370 def generate_execution_code(self, code): 6371 num_conditions = len(self.conditions) 6372 line_tracing_enabled = code.globalstate.directives['linetrace'] 6373 for i, cond in enumerate(self.conditions, 1): 6374 code.putln("case %s:" % cond.result()) 6375 code.mark_pos(cond.pos) # Tracing code must appear *after* the 'case' statement. 6376 if line_tracing_enabled and i < num_conditions: 6377 # Allow fall-through after the line tracing code. 6378 code.putln('CYTHON_FALLTHROUGH;') 6379 self.body.generate_execution_code(code) 6380 code.mark_pos(self.pos, trace=False) 6381 code.putln("break;") 6382 6383 def generate_function_definitions(self, env, code): 6384 for cond in self.conditions: 6385 cond.generate_function_definitions(env, code) 6386 self.body.generate_function_definitions(env, code) 6387 6388 def annotate(self, code): 6389 for cond in self.conditions: 6390 cond.annotate(code) 6391 self.body.annotate(code) 6392 6393 6394class SwitchStatNode(StatNode): 6395 # Generated in the optimization of an if-elif-else node 6396 # 6397 # test ExprNode 6398 # cases [SwitchCaseNode] 6399 # else_clause StatNode or None 6400 6401 child_attrs = ['test', 'cases', 'else_clause'] 6402 6403 def generate_execution_code(self, code): 6404 self.test.generate_evaluation_code(code) 6405 # Make sure all conditions are evaluated before going into the switch() statement. 6406 # This is required in order to prevent any execution code from leaking into the space between the cases. 6407 for case in self.cases: 6408 case.generate_condition_evaluation_code(code) 6409 code.mark_pos(self.pos) 6410 code.putln("switch (%s) {" % self.test.result()) 6411 for case in self.cases: 6412 case.generate_execution_code(code) 6413 if self.else_clause is not None: 6414 code.putln("default:") 6415 self.else_clause.generate_execution_code(code) 6416 code.putln("break;") 6417 else: 6418 # Always generate a default clause to prevent C compiler warnings 6419 # about unmatched enum values (it was not the user who decided to 6420 # generate the switch statement, so shouldn't be bothered). 6421 code.putln("default: break;") 6422 code.putln("}") 6423 self.test.generate_disposal_code(code) 6424 self.test.free_temps(code) 6425 6426 def generate_function_definitions(self, env, code): 6427 self.test.generate_function_definitions(env, code) 6428 for case in self.cases: 6429 case.generate_function_definitions(env, code) 6430 if self.else_clause is not None: 6431 self.else_clause.generate_function_definitions(env, code) 6432 6433 def annotate(self, code): 6434 self.test.annotate(code) 6435 for case in self.cases: 6436 case.annotate(code) 6437 if self.else_clause is not None: 6438 self.else_clause.annotate(code) 6439 6440 6441class LoopNode(object): 6442 pass 6443 6444 6445class WhileStatNode(LoopNode, StatNode): 6446 # while statement 6447 # 6448 # condition ExprNode 6449 # body StatNode 6450 # else_clause StatNode 6451 6452 child_attrs = ["condition", "body", "else_clause"] 6453 6454 def analyse_declarations(self, env): 6455 self.body.analyse_declarations(env) 6456 if self.else_clause: 6457 self.else_clause.analyse_declarations(env) 6458 6459 def analyse_expressions(self, env): 6460 if self.condition: 6461 self.condition = self.condition.analyse_temp_boolean_expression(env) 6462 self.body = self.body.analyse_expressions(env) 6463 if self.else_clause: 6464 self.else_clause = self.else_clause.analyse_expressions(env) 6465 return self 6466 6467 def generate_execution_code(self, code): 6468 code.mark_pos(self.pos) 6469 old_loop_labels = code.new_loop_labels() 6470 code.putln( 6471 "while (1) {") 6472 if self.condition: 6473 self.condition.generate_evaluation_code(code) 6474 self.condition.generate_disposal_code(code) 6475 code.putln( 6476 "if (!%s) break;" % self.condition.result()) 6477 self.condition.free_temps(code) 6478 self.body.generate_execution_code(code) 6479 code.put_label(code.continue_label) 6480 code.putln("}") 6481 break_label = code.break_label 6482 code.set_loop_labels(old_loop_labels) 6483 if self.else_clause: 6484 code.mark_pos(self.else_clause.pos) 6485 code.putln("/*else*/ {") 6486 self.else_clause.generate_execution_code(code) 6487 code.putln("}") 6488 code.put_label(break_label) 6489 6490 def generate_function_definitions(self, env, code): 6491 if self.condition: 6492 self.condition.generate_function_definitions(env, code) 6493 self.body.generate_function_definitions(env, code) 6494 if self.else_clause is not None: 6495 self.else_clause.generate_function_definitions(env, code) 6496 6497 def annotate(self, code): 6498 if self.condition: 6499 self.condition.annotate(code) 6500 self.body.annotate(code) 6501 if self.else_clause: 6502 self.else_clause.annotate(code) 6503 6504 6505class DictIterationNextNode(Node): 6506 # Helper node for calling PyDict_Next() inside of a WhileStatNode 6507 # and checking the dictionary size for changes. Created in 6508 # Optimize.py. 6509 child_attrs = ['dict_obj', 'expected_size', 'pos_index_var', 6510 'coerced_key_var', 'coerced_value_var', 'coerced_tuple_var', 6511 'key_target', 'value_target', 'tuple_target', 'is_dict_flag'] 6512 6513 coerced_key_var = key_ref = None 6514 coerced_value_var = value_ref = None 6515 coerced_tuple_var = tuple_ref = None 6516 6517 def __init__(self, dict_obj, expected_size, pos_index_var, 6518 key_target, value_target, tuple_target, is_dict_flag): 6519 Node.__init__( 6520 self, dict_obj.pos, 6521 dict_obj=dict_obj, 6522 expected_size=expected_size, 6523 pos_index_var=pos_index_var, 6524 key_target=key_target, 6525 value_target=value_target, 6526 tuple_target=tuple_target, 6527 is_dict_flag=is_dict_flag, 6528 is_temp=True, 6529 type=PyrexTypes.c_bint_type) 6530 6531 def analyse_expressions(self, env): 6532 from . import ExprNodes 6533 self.dict_obj = self.dict_obj.analyse_types(env) 6534 self.expected_size = self.expected_size.analyse_types(env) 6535 if self.pos_index_var: 6536 self.pos_index_var = self.pos_index_var.analyse_types(env) 6537 if self.key_target: 6538 self.key_target = self.key_target.analyse_target_types(env) 6539 self.key_ref = ExprNodes.TempNode(self.key_target.pos, PyrexTypes.py_object_type) 6540 self.coerced_key_var = self.key_ref.coerce_to(self.key_target.type, env) 6541 if self.value_target: 6542 self.value_target = self.value_target.analyse_target_types(env) 6543 self.value_ref = ExprNodes.TempNode(self.value_target.pos, type=PyrexTypes.py_object_type) 6544 self.coerced_value_var = self.value_ref.coerce_to(self.value_target.type, env) 6545 if self.tuple_target: 6546 self.tuple_target = self.tuple_target.analyse_target_types(env) 6547 self.tuple_ref = ExprNodes.TempNode(self.tuple_target.pos, PyrexTypes.py_object_type) 6548 self.coerced_tuple_var = self.tuple_ref.coerce_to(self.tuple_target.type, env) 6549 self.is_dict_flag = self.is_dict_flag.analyse_types(env) 6550 return self 6551 6552 def generate_function_definitions(self, env, code): 6553 self.dict_obj.generate_function_definitions(env, code) 6554 6555 def generate_execution_code(self, code): 6556 code.globalstate.use_utility_code(UtilityCode.load_cached("dict_iter", "Optimize.c")) 6557 self.dict_obj.generate_evaluation_code(code) 6558 6559 assignments = [] 6560 temp_addresses = [] 6561 for var, result, target in [(self.key_ref, self.coerced_key_var, self.key_target), 6562 (self.value_ref, self.coerced_value_var, self.value_target), 6563 (self.tuple_ref, self.coerced_tuple_var, self.tuple_target)]: 6564 if target is None: 6565 addr = 'NULL' 6566 else: 6567 assignments.append((var, result, target)) 6568 var.allocate(code) 6569 addr = '&%s' % var.result() 6570 temp_addresses.append(addr) 6571 6572 result_temp = code.funcstate.allocate_temp(PyrexTypes.c_int_type, False) 6573 code.putln("%s = __Pyx_dict_iter_next(%s, %s, &%s, %s, %s, %s, %s);" % ( 6574 result_temp, 6575 self.dict_obj.py_result(), 6576 self.expected_size.result(), 6577 self.pos_index_var.result(), 6578 temp_addresses[0], 6579 temp_addresses[1], 6580 temp_addresses[2], 6581 self.is_dict_flag.result() 6582 )) 6583 code.putln("if (unlikely(%s == 0)) break;" % result_temp) 6584 code.putln(code.error_goto_if("%s == -1" % result_temp, self.pos)) 6585 code.funcstate.release_temp(result_temp) 6586 6587 # evaluate all coercions before the assignments 6588 for var, result, target in assignments: 6589 code.put_gotref(var.result()) 6590 for var, result, target in assignments: 6591 result.generate_evaluation_code(code) 6592 for var, result, target in assignments: 6593 target.generate_assignment_code(result, code) 6594 var.release(code) 6595 6596 6597class SetIterationNextNode(Node): 6598 # Helper node for calling _PySet_NextEntry() inside of a WhileStatNode 6599 # and checking the set size for changes. Created in Optimize.py. 6600 child_attrs = ['set_obj', 'expected_size', 'pos_index_var', 6601 'coerced_value_var', 'value_target', 'is_set_flag'] 6602 6603 coerced_value_var = value_ref = None 6604 6605 def __init__(self, set_obj, expected_size, pos_index_var, value_target, is_set_flag): 6606 Node.__init__( 6607 self, set_obj.pos, 6608 set_obj=set_obj, 6609 expected_size=expected_size, 6610 pos_index_var=pos_index_var, 6611 value_target=value_target, 6612 is_set_flag=is_set_flag, 6613 is_temp=True, 6614 type=PyrexTypes.c_bint_type) 6615 6616 def analyse_expressions(self, env): 6617 from . import ExprNodes 6618 self.set_obj = self.set_obj.analyse_types(env) 6619 self.expected_size = self.expected_size.analyse_types(env) 6620 self.pos_index_var = self.pos_index_var.analyse_types(env) 6621 self.value_target = self.value_target.analyse_target_types(env) 6622 self.value_ref = ExprNodes.TempNode(self.value_target.pos, type=PyrexTypes.py_object_type) 6623 self.coerced_value_var = self.value_ref.coerce_to(self.value_target.type, env) 6624 self.is_set_flag = self.is_set_flag.analyse_types(env) 6625 return self 6626 6627 def generate_function_definitions(self, env, code): 6628 self.set_obj.generate_function_definitions(env, code) 6629 6630 def generate_execution_code(self, code): 6631 code.globalstate.use_utility_code(UtilityCode.load_cached("set_iter", "Optimize.c")) 6632 self.set_obj.generate_evaluation_code(code) 6633 6634 value_ref = self.value_ref 6635 value_ref.allocate(code) 6636 6637 result_temp = code.funcstate.allocate_temp(PyrexTypes.c_int_type, False) 6638 code.putln("%s = __Pyx_set_iter_next(%s, %s, &%s, &%s, %s);" % ( 6639 result_temp, 6640 self.set_obj.py_result(), 6641 self.expected_size.result(), 6642 self.pos_index_var.result(), 6643 value_ref.result(), 6644 self.is_set_flag.result() 6645 )) 6646 code.putln("if (unlikely(%s == 0)) break;" % result_temp) 6647 code.putln(code.error_goto_if("%s == -1" % result_temp, self.pos)) 6648 code.funcstate.release_temp(result_temp) 6649 6650 # evaluate all coercions before the assignments 6651 code.put_gotref(value_ref.result()) 6652 self.coerced_value_var.generate_evaluation_code(code) 6653 self.value_target.generate_assignment_code(self.coerced_value_var, code) 6654 value_ref.release(code) 6655 6656 6657def ForStatNode(pos, **kw): 6658 if 'iterator' in kw: 6659 if kw['iterator'].is_async: 6660 return AsyncForStatNode(pos, **kw) 6661 else: 6662 return ForInStatNode(pos, **kw) 6663 else: 6664 return ForFromStatNode(pos, **kw) 6665 6666 6667class _ForInStatNode(LoopNode, StatNode): 6668 # Base class of 'for-in' statements. 6669 # 6670 # target ExprNode 6671 # iterator IteratorNode | AIterAwaitExprNode(AsyncIteratorNode) 6672 # body StatNode 6673 # else_clause StatNode 6674 # item NextNode | AwaitExprNode(AsyncNextNode) 6675 # is_async boolean true for 'async for' statements 6676 6677 child_attrs = ["target", "item", "iterator", "body", "else_clause"] 6678 item = None 6679 is_async = False 6680 6681 def _create_item_node(self): 6682 raise NotImplementedError("must be implemented by subclasses") 6683 6684 def analyse_declarations(self, env): 6685 self.target.analyse_target_declaration(env) 6686 self.body.analyse_declarations(env) 6687 if self.else_clause: 6688 self.else_clause.analyse_declarations(env) 6689 self._create_item_node() 6690 6691 def analyse_expressions(self, env): 6692 self.target = self.target.analyse_target_types(env) 6693 self.iterator = self.iterator.analyse_expressions(env) 6694 self._create_item_node() # must rewrap self.item after analysis 6695 self.item = self.item.analyse_expressions(env) 6696 if (not self.is_async and 6697 (self.iterator.type.is_ptr or self.iterator.type.is_array) and 6698 self.target.type.assignable_from(self.iterator.type)): 6699 # C array slice optimization. 6700 pass 6701 else: 6702 self.item = self.item.coerce_to(self.target.type, env) 6703 self.body = self.body.analyse_expressions(env) 6704 if self.else_clause: 6705 self.else_clause = self.else_clause.analyse_expressions(env) 6706 return self 6707 6708 def generate_execution_code(self, code): 6709 code.mark_pos(self.pos) 6710 old_loop_labels = code.new_loop_labels() 6711 self.iterator.generate_evaluation_code(code) 6712 code.putln("for (;;) {") 6713 self.item.generate_evaluation_code(code) 6714 self.target.generate_assignment_code(self.item, code) 6715 self.body.generate_execution_code(code) 6716 code.mark_pos(self.pos) 6717 code.put_label(code.continue_label) 6718 code.putln("}") 6719 break_label = code.break_label 6720 code.set_loop_labels(old_loop_labels) 6721 6722 if self.else_clause: 6723 # in nested loops, the 'else' block can contain a 6724 # 'continue' statement for the outer loop, but we may need 6725 # to generate cleanup code before taking that path, so we 6726 # intercept it here 6727 orig_continue_label = code.continue_label 6728 code.continue_label = code.new_label('outer_continue') 6729 6730 code.putln("/*else*/ {") 6731 self.else_clause.generate_execution_code(code) 6732 code.putln("}") 6733 6734 if code.label_used(code.continue_label): 6735 code.put_goto(break_label) 6736 code.mark_pos(self.pos) 6737 code.put_label(code.continue_label) 6738 self.iterator.generate_disposal_code(code) 6739 code.put_goto(orig_continue_label) 6740 code.set_loop_labels(old_loop_labels) 6741 6742 code.mark_pos(self.pos) 6743 if code.label_used(break_label): 6744 code.put_label(break_label) 6745 self.iterator.generate_disposal_code(code) 6746 self.iterator.free_temps(code) 6747 6748 def generate_function_definitions(self, env, code): 6749 self.target.generate_function_definitions(env, code) 6750 self.iterator.generate_function_definitions(env, code) 6751 self.body.generate_function_definitions(env, code) 6752 if self.else_clause is not None: 6753 self.else_clause.generate_function_definitions(env, code) 6754 6755 def annotate(self, code): 6756 self.target.annotate(code) 6757 self.iterator.annotate(code) 6758 self.body.annotate(code) 6759 if self.else_clause: 6760 self.else_clause.annotate(code) 6761 self.item.annotate(code) 6762 6763 6764class ForInStatNode(_ForInStatNode): 6765 # 'for' statement 6766 6767 is_async = False 6768 6769 def _create_item_node(self): 6770 from .ExprNodes import NextNode 6771 self.item = NextNode(self.iterator) 6772 6773 6774class AsyncForStatNode(_ForInStatNode): 6775 # 'async for' statement 6776 # 6777 # iterator AIterAwaitExprNode(AsyncIteratorNode) 6778 # item AwaitIterNextExprNode(AsyncIteratorNode) 6779 6780 is_async = True 6781 6782 def __init__(self, pos, **kw): 6783 assert 'item' not in kw 6784 from . import ExprNodes 6785 # AwaitExprNodes must appear before running MarkClosureVisitor 6786 kw['item'] = ExprNodes.AwaitIterNextExprNode(kw['iterator'].pos, arg=None) 6787 _ForInStatNode.__init__(self, pos, **kw) 6788 6789 def _create_item_node(self): 6790 from . import ExprNodes 6791 self.item.arg = ExprNodes.AsyncNextNode(self.iterator) 6792 6793 6794class ForFromStatNode(LoopNode, StatNode): 6795 # for name from expr rel name rel expr 6796 # 6797 # target NameNode 6798 # bound1 ExprNode 6799 # relation1 string 6800 # relation2 string 6801 # bound2 ExprNode 6802 # step ExprNode or None 6803 # body StatNode 6804 # else_clause StatNode or None 6805 # 6806 # Used internally: 6807 # 6808 # from_range bool 6809 # is_py_target bool 6810 # loopvar_node ExprNode (usually a NameNode or temp node) 6811 # py_loopvar_node PyTempNode or None 6812 child_attrs = ["target", "bound1", "bound2", "step", "body", "else_clause"] 6813 6814 is_py_target = False 6815 loopvar_node = None 6816 py_loopvar_node = None 6817 from_range = False 6818 6819 gil_message = "For-loop using object bounds or target" 6820 6821 def nogil_check(self, env): 6822 for x in (self.target, self.bound1, self.bound2): 6823 if x.type.is_pyobject: 6824 self.gil_error() 6825 6826 def analyse_declarations(self, env): 6827 self.target.analyse_target_declaration(env) 6828 self.body.analyse_declarations(env) 6829 if self.else_clause: 6830 self.else_clause.analyse_declarations(env) 6831 6832 def analyse_expressions(self, env): 6833 from . import ExprNodes 6834 self.target = self.target.analyse_target_types(env) 6835 self.bound1 = self.bound1.analyse_types(env) 6836 self.bound2 = self.bound2.analyse_types(env) 6837 if self.step is not None: 6838 if isinstance(self.step, ExprNodes.UnaryMinusNode): 6839 warning(self.step.pos, "Probable infinite loop in for-from-by statement. " 6840 "Consider switching the directions of the relations.", 2) 6841 self.step = self.step.analyse_types(env) 6842 6843 self.set_up_loop(env) 6844 target_type = self.target.type 6845 if not (target_type.is_pyobject or target_type.is_numeric): 6846 error(self.target.pos, "for-from loop variable must be c numeric type or Python object") 6847 6848 self.body = self.body.analyse_expressions(env) 6849 if self.else_clause: 6850 self.else_clause = self.else_clause.analyse_expressions(env) 6851 return self 6852 6853 def set_up_loop(self, env): 6854 from . import ExprNodes 6855 6856 target_type = self.target.type 6857 if target_type.is_numeric: 6858 loop_type = target_type 6859 else: 6860 if target_type.is_enum: 6861 warning(self.target.pos, 6862 "Integer loops over enum values are fragile. Please cast to a safe integer type instead.") 6863 loop_type = PyrexTypes.c_long_type if target_type.is_pyobject else PyrexTypes.c_int_type 6864 if not self.bound1.type.is_pyobject: 6865 loop_type = PyrexTypes.widest_numeric_type(loop_type, self.bound1.type) 6866 if not self.bound2.type.is_pyobject: 6867 loop_type = PyrexTypes.widest_numeric_type(loop_type, self.bound2.type) 6868 if self.step is not None and not self.step.type.is_pyobject: 6869 loop_type = PyrexTypes.widest_numeric_type(loop_type, self.step.type) 6870 self.bound1 = self.bound1.coerce_to(loop_type, env) 6871 self.bound2 = self.bound2.coerce_to(loop_type, env) 6872 if not self.bound2.is_literal: 6873 self.bound2 = self.bound2.coerce_to_temp(env) 6874 if self.step is not None: 6875 self.step = self.step.coerce_to(loop_type, env) 6876 if not self.step.is_literal: 6877 self.step = self.step.coerce_to_temp(env) 6878 6879 if target_type.is_numeric or target_type.is_enum: 6880 self.is_py_target = False 6881 if isinstance(self.target, ExprNodes.BufferIndexNode): 6882 raise error(self.pos, "Buffer or memoryview slicing/indexing not allowed as for-loop target.") 6883 self.loopvar_node = self.target 6884 self.py_loopvar_node = None 6885 else: 6886 self.is_py_target = True 6887 c_loopvar_node = ExprNodes.TempNode(self.pos, loop_type, env) 6888 self.loopvar_node = c_loopvar_node 6889 self.py_loopvar_node = ExprNodes.CloneNode(c_loopvar_node).coerce_to_pyobject(env) 6890 6891 def generate_execution_code(self, code): 6892 code.mark_pos(self.pos) 6893 old_loop_labels = code.new_loop_labels() 6894 from_range = self.from_range 6895 self.bound1.generate_evaluation_code(code) 6896 self.bound2.generate_evaluation_code(code) 6897 offset, incop = self.relation_table[self.relation1] 6898 if self.step is not None: 6899 self.step.generate_evaluation_code(code) 6900 step = self.step.result() 6901 incop = "%s=%s" % (incop[0], step) # e.g. '++' => '+= STEP' 6902 else: 6903 step = '1' 6904 6905 from . import ExprNodes 6906 if isinstance(self.loopvar_node, ExprNodes.TempNode): 6907 self.loopvar_node.allocate(code) 6908 if isinstance(self.py_loopvar_node, ExprNodes.TempNode): 6909 self.py_loopvar_node.allocate(code) 6910 6911 loopvar_type = PyrexTypes.c_long_type if self.target.type.is_enum else self.target.type 6912 6913 if from_range and not self.is_py_target: 6914 loopvar_name = code.funcstate.allocate_temp(loopvar_type, False) 6915 else: 6916 loopvar_name = self.loopvar_node.result() 6917 if loopvar_type.is_int and not loopvar_type.signed and self.relation2[0] == '>': 6918 # Handle the case where the endpoint of an unsigned int iteration 6919 # is within step of 0. 6920 code.putln("for (%s = %s%s + %s; %s %s %s + %s; ) { %s%s;" % ( 6921 loopvar_name, 6922 self.bound1.result(), offset, step, 6923 loopvar_name, self.relation2, self.bound2.result(), step, 6924 loopvar_name, incop)) 6925 else: 6926 code.putln("for (%s = %s%s; %s %s %s; %s%s) {" % ( 6927 loopvar_name, 6928 self.bound1.result(), offset, 6929 loopvar_name, self.relation2, self.bound2.result(), 6930 loopvar_name, incop)) 6931 6932 coerced_loopvar_node = self.py_loopvar_node 6933 if coerced_loopvar_node is None and from_range: 6934 coerced_loopvar_node = ExprNodes.RawCNameExprNode(self.target.pos, loopvar_type, loopvar_name) 6935 if coerced_loopvar_node is not None: 6936 coerced_loopvar_node.generate_evaluation_code(code) 6937 self.target.generate_assignment_code(coerced_loopvar_node, code) 6938 6939 self.body.generate_execution_code(code) 6940 code.put_label(code.continue_label) 6941 6942 if not from_range and self.py_loopvar_node: 6943 # This mess is to make for..from loops with python targets behave 6944 # exactly like those with C targets with regards to re-assignment 6945 # of the loop variable. 6946 if self.target.entry.is_pyglobal: 6947 # We know target is a NameNode, this is the only ugly case. 6948 target_node = ExprNodes.PyTempNode(self.target.pos, None) 6949 target_node.allocate(code) 6950 interned_cname = code.intern_identifier(self.target.entry.name) 6951 if self.target.entry.scope.is_module_scope: 6952 code.globalstate.use_utility_code( 6953 UtilityCode.load_cached("GetModuleGlobalName", "ObjectHandling.c")) 6954 lookup_func = '__Pyx_GetModuleGlobalName(%s, %s); %s' 6955 else: 6956 code.globalstate.use_utility_code( 6957 UtilityCode.load_cached("GetNameInClass", "ObjectHandling.c")) 6958 lookup_func = '__Pyx_GetNameInClass(%s, {}, %s); %s'.format( 6959 self.target.entry.scope.namespace_cname) 6960 code.putln(lookup_func % ( 6961 target_node.result(), 6962 interned_cname, 6963 code.error_goto_if_null(target_node.result(), self.target.pos))) 6964 code.put_gotref(target_node.result()) 6965 else: 6966 target_node = self.target 6967 from_py_node = ExprNodes.CoerceFromPyTypeNode( 6968 self.loopvar_node.type, target_node, self.target.entry.scope) 6969 from_py_node.temp_code = loopvar_name 6970 from_py_node.generate_result_code(code) 6971 if self.target.entry.is_pyglobal: 6972 code.put_decref(target_node.result(), target_node.type) 6973 target_node.release(code) 6974 6975 code.putln("}") 6976 6977 if not from_range and self.py_loopvar_node: 6978 # This is potentially wasteful, but we don't want the semantics to 6979 # depend on whether or not the loop is a python type. 6980 self.py_loopvar_node.generate_evaluation_code(code) 6981 self.target.generate_assignment_code(self.py_loopvar_node, code) 6982 if from_range and not self.is_py_target: 6983 code.funcstate.release_temp(loopvar_name) 6984 6985 break_label = code.break_label 6986 code.set_loop_labels(old_loop_labels) 6987 if self.else_clause: 6988 code.putln("/*else*/ {") 6989 self.else_clause.generate_execution_code(code) 6990 code.putln("}") 6991 code.put_label(break_label) 6992 self.bound1.generate_disposal_code(code) 6993 self.bound1.free_temps(code) 6994 self.bound2.generate_disposal_code(code) 6995 self.bound2.free_temps(code) 6996 if isinstance(self.loopvar_node, ExprNodes.TempNode): 6997 self.loopvar_node.release(code) 6998 if isinstance(self.py_loopvar_node, ExprNodes.TempNode): 6999 self.py_loopvar_node.release(code) 7000 if self.step is not None: 7001 self.step.generate_disposal_code(code) 7002 self.step.free_temps(code) 7003 7004 relation_table = { 7005 # {relop : (initial offset, increment op)} 7006 '<=': ("", "++"), 7007 '<' : ("+1", "++"), 7008 '>=': ("", "--"), 7009 '>' : ("-1", "--"), 7010 } 7011 7012 def generate_function_definitions(self, env, code): 7013 self.target.generate_function_definitions(env, code) 7014 self.bound1.generate_function_definitions(env, code) 7015 self.bound2.generate_function_definitions(env, code) 7016 if self.step is not None: 7017 self.step.generate_function_definitions(env, code) 7018 self.body.generate_function_definitions(env, code) 7019 if self.else_clause is not None: 7020 self.else_clause.generate_function_definitions(env, code) 7021 7022 def annotate(self, code): 7023 self.target.annotate(code) 7024 self.bound1.annotate(code) 7025 self.bound2.annotate(code) 7026 if self.step: 7027 self.step.annotate(code) 7028 self.body.annotate(code) 7029 if self.else_clause: 7030 self.else_clause.annotate(code) 7031 7032 7033class WithStatNode(StatNode): 7034 """ 7035 Represents a Python with statement. 7036 7037 Implemented by the WithTransform as follows: 7038 7039 MGR = EXPR 7040 EXIT = MGR.__exit__ 7041 VALUE = MGR.__enter__() 7042 EXC = True 7043 try: 7044 try: 7045 TARGET = VALUE # optional 7046 BODY 7047 except: 7048 EXC = False 7049 if not EXIT(*EXCINFO): 7050 raise 7051 finally: 7052 if EXC: 7053 EXIT(None, None, None) 7054 MGR = EXIT = VALUE = None 7055 """ 7056 # manager The with statement manager object 7057 # target ExprNode the target lhs of the __enter__() call 7058 # body StatNode 7059 # enter_call ExprNode the call to the __enter__() method 7060 # exit_var String the cname of the __exit__() method reference 7061 7062 child_attrs = ["manager", "enter_call", "target", "body"] 7063 7064 enter_call = None 7065 target_temp = None 7066 7067 def analyse_declarations(self, env): 7068 self.manager.analyse_declarations(env) 7069 self.enter_call.analyse_declarations(env) 7070 self.body.analyse_declarations(env) 7071 7072 def analyse_expressions(self, env): 7073 self.manager = self.manager.analyse_types(env) 7074 self.enter_call = self.enter_call.analyse_types(env) 7075 if self.target: 7076 # set up target_temp before descending into body (which uses it) 7077 from .ExprNodes import TempNode 7078 self.target_temp = TempNode(self.enter_call.pos, self.enter_call.type) 7079 self.body = self.body.analyse_expressions(env) 7080 return self 7081 7082 def generate_function_definitions(self, env, code): 7083 self.manager.generate_function_definitions(env, code) 7084 self.enter_call.generate_function_definitions(env, code) 7085 self.body.generate_function_definitions(env, code) 7086 7087 def generate_execution_code(self, code): 7088 code.mark_pos(self.pos) 7089 code.putln("/*with:*/ {") 7090 self.manager.generate_evaluation_code(code) 7091 self.exit_var = code.funcstate.allocate_temp(py_object_type, manage_ref=False) 7092 code.globalstate.use_utility_code( 7093 UtilityCode.load_cached("PyObjectLookupSpecial", "ObjectHandling.c")) 7094 code.putln("%s = __Pyx_PyObject_LookupSpecial(%s, %s); %s" % ( 7095 self.exit_var, 7096 self.manager.py_result(), 7097 code.intern_identifier(EncodedString('__aexit__' if self.is_async else '__exit__')), 7098 code.error_goto_if_null(self.exit_var, self.pos), 7099 )) 7100 code.put_gotref(self.exit_var) 7101 7102 # need to free exit_var in the face of exceptions during setup 7103 old_error_label = code.new_error_label() 7104 intermediate_error_label = code.error_label 7105 7106 self.enter_call.generate_evaluation_code(code) 7107 if self.target: 7108 # The temp result will be cleaned up by the WithTargetAssignmentStatNode 7109 # after assigning its result to the target of the 'with' statement. 7110 self.target_temp.allocate(code) 7111 self.enter_call.make_owned_reference(code) 7112 code.putln("%s = %s;" % (self.target_temp.result(), self.enter_call.result())) 7113 self.enter_call.generate_post_assignment_code(code) 7114 else: 7115 self.enter_call.generate_disposal_code(code) 7116 self.enter_call.free_temps(code) 7117 7118 self.manager.generate_disposal_code(code) 7119 self.manager.free_temps(code) 7120 7121 code.error_label = old_error_label 7122 self.body.generate_execution_code(code) 7123 7124 if code.label_used(intermediate_error_label): 7125 step_over_label = code.new_label() 7126 code.put_goto(step_over_label) 7127 code.put_label(intermediate_error_label) 7128 code.put_decref_clear(self.exit_var, py_object_type) 7129 code.put_goto(old_error_label) 7130 code.put_label(step_over_label) 7131 7132 code.funcstate.release_temp(self.exit_var) 7133 code.putln('}') 7134 7135 7136class WithTargetAssignmentStatNode(AssignmentNode): 7137 # The target assignment of the 'with' statement value (return 7138 # value of the __enter__() call). 7139 # 7140 # This is a special cased assignment that properly cleans up the RHS. 7141 # 7142 # lhs ExprNode the assignment target 7143 # rhs ExprNode a (coerced) TempNode for the rhs (from WithStatNode) 7144 # with_node WithStatNode the surrounding with-statement 7145 7146 child_attrs = ["rhs", "lhs"] 7147 with_node = None 7148 rhs = None 7149 7150 def analyse_declarations(self, env): 7151 self.lhs.analyse_target_declaration(env) 7152 7153 def analyse_expressions(self, env): 7154 self.lhs = self.lhs.analyse_target_types(env) 7155 self.lhs.gil_assignment_check(env) 7156 self.rhs = self.with_node.target_temp.coerce_to(self.lhs.type, env) 7157 return self 7158 7159 def generate_execution_code(self, code): 7160 self.rhs.generate_evaluation_code(code) 7161 self.lhs.generate_assignment_code(self.rhs, code) 7162 self.with_node.target_temp.release(code) 7163 7164 def annotate(self, code): 7165 self.lhs.annotate(code) 7166 self.rhs.annotate(code) 7167 7168 7169class TryExceptStatNode(StatNode): 7170 # try .. except statement 7171 # 7172 # body StatNode 7173 # except_clauses [ExceptClauseNode] 7174 # else_clause StatNode or None 7175 7176 child_attrs = ["body", "except_clauses", "else_clause"] 7177 in_generator = False 7178 7179 def analyse_declarations(self, env): 7180 self.body.analyse_declarations(env) 7181 for except_clause in self.except_clauses: 7182 except_clause.analyse_declarations(env) 7183 if self.else_clause: 7184 self.else_clause.analyse_declarations(env) 7185 7186 def analyse_expressions(self, env): 7187 self.body = self.body.analyse_expressions(env) 7188 default_clause_seen = 0 7189 for i, except_clause in enumerate(self.except_clauses): 7190 except_clause = self.except_clauses[i] = except_clause.analyse_expressions(env) 7191 if default_clause_seen: 7192 error(except_clause.pos, "default 'except:' must be last") 7193 if not except_clause.pattern: 7194 default_clause_seen = 1 7195 self.has_default_clause = default_clause_seen 7196 if self.else_clause: 7197 self.else_clause = self.else_clause.analyse_expressions(env) 7198 return self 7199 7200 nogil_check = Node.gil_error 7201 gil_message = "Try-except statement" 7202 7203 def generate_execution_code(self, code): 7204 code.mark_pos(self.pos) # before changing the error label, in case of tracing errors 7205 code.putln("{") 7206 7207 old_return_label = code.return_label 7208 old_break_label = code.break_label 7209 old_continue_label = code.continue_label 7210 old_error_label = code.new_error_label() 7211 our_error_label = code.error_label 7212 except_end_label = code.new_label('exception_handled') 7213 except_error_label = code.new_label('except_error') 7214 except_return_label = code.new_label('except_return') 7215 try_return_label = code.new_label('try_return') 7216 try_break_label = code.new_label('try_break') if old_break_label else None 7217 try_continue_label = code.new_label('try_continue') if old_continue_label else None 7218 try_end_label = code.new_label('try_end') 7219 7220 exc_save_vars = [code.funcstate.allocate_temp(py_object_type, False) 7221 for _ in range(3)] 7222 save_exc = code.insertion_point() 7223 code.putln( 7224 "/*try:*/ {") 7225 code.return_label = try_return_label 7226 code.break_label = try_break_label 7227 code.continue_label = try_continue_label 7228 self.body.generate_execution_code(code) 7229 code.mark_pos(self.pos, trace=False) 7230 code.putln( 7231 "}") 7232 temps_to_clean_up = code.funcstate.all_free_managed_temps() 7233 can_raise = code.label_used(our_error_label) 7234 7235 if can_raise: 7236 # inject code before the try block to save away the exception state 7237 code.globalstate.use_utility_code(reset_exception_utility_code) 7238 if not self.in_generator: 7239 save_exc.putln("__Pyx_PyThreadState_declare") 7240 save_exc.putln("__Pyx_PyThreadState_assign") 7241 save_exc.putln("__Pyx_ExceptionSave(%s);" % ( 7242 ', '.join(['&%s' % var for var in exc_save_vars]))) 7243 for var in exc_save_vars: 7244 save_exc.put_xgotref(var) 7245 7246 def restore_saved_exception(): 7247 for name in exc_save_vars: 7248 code.put_xgiveref(name) 7249 code.putln("__Pyx_ExceptionReset(%s);" % 7250 ', '.join(exc_save_vars)) 7251 else: 7252 # try block cannot raise exceptions, but we had to allocate the temps above, 7253 # so just keep the C compiler from complaining about them being unused 7254 mark_vars_used = ["(void)%s;" % var for var in exc_save_vars] 7255 save_exc.putln("%s /* mark used */" % ' '.join(mark_vars_used)) 7256 7257 def restore_saved_exception(): 7258 pass 7259 7260 code.error_label = except_error_label 7261 code.return_label = except_return_label 7262 normal_case_terminates = self.body.is_terminator 7263 if self.else_clause: 7264 code.mark_pos(self.else_clause.pos) 7265 code.putln( 7266 "/*else:*/ {") 7267 self.else_clause.generate_execution_code(code) 7268 code.putln( 7269 "}") 7270 if not normal_case_terminates: 7271 normal_case_terminates = self.else_clause.is_terminator 7272 7273 if can_raise: 7274 if not normal_case_terminates: 7275 for var in exc_save_vars: 7276 code.put_xdecref_clear(var, py_object_type) 7277 code.put_goto(try_end_label) 7278 code.put_label(our_error_label) 7279 for temp_name, temp_type in temps_to_clean_up: 7280 code.put_xdecref_clear(temp_name, temp_type) 7281 7282 outer_except = code.funcstate.current_except 7283 # Currently points to self, but the ExceptClauseNode would also be ok. Change if needed. 7284 code.funcstate.current_except = self 7285 for except_clause in self.except_clauses: 7286 except_clause.generate_handling_code(code, except_end_label) 7287 code.funcstate.current_except = outer_except 7288 7289 if not self.has_default_clause: 7290 code.put_goto(except_error_label) 7291 7292 for exit_label, old_label in [(except_error_label, old_error_label), 7293 (try_break_label, old_break_label), 7294 (try_continue_label, old_continue_label), 7295 (try_return_label, old_return_label), 7296 (except_return_label, old_return_label)]: 7297 if code.label_used(exit_label): 7298 if not normal_case_terminates and not code.label_used(try_end_label): 7299 code.put_goto(try_end_label) 7300 code.put_label(exit_label) 7301 code.mark_pos(self.pos, trace=False) 7302 if can_raise: 7303 restore_saved_exception() 7304 code.put_goto(old_label) 7305 7306 if code.label_used(except_end_label): 7307 if not normal_case_terminates and not code.label_used(try_end_label): 7308 code.put_goto(try_end_label) 7309 code.put_label(except_end_label) 7310 if can_raise: 7311 restore_saved_exception() 7312 if code.label_used(try_end_label): 7313 code.put_label(try_end_label) 7314 code.putln("}") 7315 7316 for cname in exc_save_vars: 7317 code.funcstate.release_temp(cname) 7318 7319 code.return_label = old_return_label 7320 code.break_label = old_break_label 7321 code.continue_label = old_continue_label 7322 code.error_label = old_error_label 7323 7324 def generate_function_definitions(self, env, code): 7325 self.body.generate_function_definitions(env, code) 7326 for except_clause in self.except_clauses: 7327 except_clause.generate_function_definitions(env, code) 7328 if self.else_clause is not None: 7329 self.else_clause.generate_function_definitions(env, code) 7330 7331 def annotate(self, code): 7332 self.body.annotate(code) 7333 for except_node in self.except_clauses: 7334 except_node.annotate(code) 7335 if self.else_clause: 7336 self.else_clause.annotate(code) 7337 7338 7339class ExceptClauseNode(Node): 7340 # Part of try ... except statement. 7341 # 7342 # pattern [ExprNode] 7343 # target ExprNode or None 7344 # body StatNode 7345 # excinfo_target TupleNode(3*ResultRefNode) or None optional target for exception info (not owned here!) 7346 # match_flag string result of exception match 7347 # exc_value ExcValueNode used internally 7348 # function_name string qualified name of enclosing function 7349 # exc_vars (string * 3) local exception variables 7350 # is_except_as bool Py3-style "except ... as xyz" 7351 7352 # excinfo_target is never set by the parser, but can be set by a transform 7353 # in order to extract more extensive information about the exception as a 7354 # sys.exc_info()-style tuple into a target variable 7355 7356 child_attrs = ["pattern", "target", "body", "exc_value"] 7357 7358 exc_value = None 7359 excinfo_target = None 7360 is_except_as = False 7361 7362 def analyse_declarations(self, env): 7363 if self.target: 7364 self.target.analyse_target_declaration(env) 7365 self.body.analyse_declarations(env) 7366 7367 def analyse_expressions(self, env): 7368 self.function_name = env.qualified_name 7369 if self.pattern: 7370 # normalise/unpack self.pattern into a list 7371 for i, pattern in enumerate(self.pattern): 7372 pattern = pattern.analyse_expressions(env) 7373 self.pattern[i] = pattern.coerce_to_pyobject(env) 7374 7375 if self.target: 7376 from . import ExprNodes 7377 self.exc_value = ExprNodes.ExcValueNode(self.pos) 7378 self.target = self.target.analyse_target_expression(env, self.exc_value) 7379 7380 self.body = self.body.analyse_expressions(env) 7381 return self 7382 7383 def generate_handling_code(self, code, end_label): 7384 code.mark_pos(self.pos) 7385 7386 if self.pattern: 7387 has_non_literals = not all( 7388 pattern.is_literal or pattern.is_simple() and not pattern.is_temp 7389 for pattern in self.pattern) 7390 7391 if has_non_literals: 7392 # For non-trivial exception check expressions, hide the live exception from C-API calls. 7393 exc_vars = [code.funcstate.allocate_temp(py_object_type, manage_ref=True) 7394 for _ in range(3)] 7395 code.globalstate.use_utility_code(UtilityCode.load_cached("PyErrFetchRestore", "Exceptions.c")) 7396 code.putln("__Pyx_ErrFetch(&%s, &%s, &%s);" % tuple(exc_vars)) 7397 code.globalstate.use_utility_code(UtilityCode.load_cached("FastTypeChecks", "ModuleSetupCode.c")) 7398 exc_test_func = "__Pyx_PyErr_GivenExceptionMatches(%s, %%s)" % exc_vars[0] 7399 else: 7400 exc_vars = () 7401 code.globalstate.use_utility_code(UtilityCode.load_cached("PyErrExceptionMatches", "Exceptions.c")) 7402 exc_test_func = "__Pyx_PyErr_ExceptionMatches(%s)" 7403 7404 exc_tests = [] 7405 for pattern in self.pattern: 7406 pattern.generate_evaluation_code(code) 7407 exc_tests.append(exc_test_func % pattern.py_result()) 7408 7409 match_flag = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) 7410 code.putln("%s = %s;" % (match_flag, ' || '.join(exc_tests))) 7411 for pattern in self.pattern: 7412 pattern.generate_disposal_code(code) 7413 pattern.free_temps(code) 7414 7415 if has_non_literals: 7416 code.putln("__Pyx_ErrRestore(%s, %s, %s);" % tuple(exc_vars)) 7417 code.putln(' '.join(["%s = 0;" % var for var in exc_vars])) 7418 for temp in exc_vars: 7419 code.funcstate.release_temp(temp) 7420 7421 code.putln( 7422 "if (%s) {" % 7423 match_flag) 7424 code.funcstate.release_temp(match_flag) 7425 else: 7426 code.putln("/*except:*/ {") 7427 7428 if (not getattr(self.body, 'stats', True) 7429 and self.excinfo_target is None 7430 and self.target is None): 7431 # most simple case: no exception variable, empty body (pass) 7432 # => reset the exception state, done 7433 code.globalstate.use_utility_code(UtilityCode.load_cached("PyErrFetchRestore", "Exceptions.c")) 7434 code.putln("__Pyx_ErrRestore(0,0,0);") 7435 code.put_goto(end_label) 7436 code.putln("}") 7437 return 7438 7439 exc_vars = [code.funcstate.allocate_temp(py_object_type, manage_ref=True) 7440 for _ in range(3)] 7441 code.put_add_traceback(self.function_name) 7442 # We always have to fetch the exception value even if 7443 # there is no target, because this also normalises the 7444 # exception and stores it in the thread state. 7445 code.globalstate.use_utility_code(get_exception_utility_code) 7446 exc_args = "&%s, &%s, &%s" % tuple(exc_vars) 7447 code.putln("if (__Pyx_GetException(%s) < 0) %s" % ( 7448 exc_args, code.error_goto(self.pos))) 7449 for var in exc_vars: 7450 code.put_gotref(var) 7451 if self.target: 7452 self.exc_value.set_var(exc_vars[1]) 7453 self.exc_value.generate_evaluation_code(code) 7454 self.target.generate_assignment_code(self.exc_value, code) 7455 if self.excinfo_target is not None: 7456 for tempvar, node in zip(exc_vars, self.excinfo_target.args): 7457 node.set_var(tempvar) 7458 7459 old_break_label, old_continue_label = code.break_label, code.continue_label 7460 code.break_label = code.new_label('except_break') 7461 code.continue_label = code.new_label('except_continue') 7462 7463 old_exc_vars = code.funcstate.exc_vars 7464 code.funcstate.exc_vars = exc_vars 7465 self.body.generate_execution_code(code) 7466 code.funcstate.exc_vars = old_exc_vars 7467 7468 if not self.body.is_terminator: 7469 for var in exc_vars: 7470 # FIXME: XDECREF() is needed to allow re-raising (which clears the exc_vars), 7471 # but I don't think it's the right solution. 7472 code.put_xdecref_clear(var, py_object_type) 7473 code.put_goto(end_label) 7474 7475 for new_label, old_label in [(code.break_label, old_break_label), 7476 (code.continue_label, old_continue_label)]: 7477 if code.label_used(new_label): 7478 code.put_label(new_label) 7479 for var in exc_vars: 7480 code.put_decref_clear(var, py_object_type) 7481 code.put_goto(old_label) 7482 code.break_label = old_break_label 7483 code.continue_label = old_continue_label 7484 7485 for temp in exc_vars: 7486 code.funcstate.release_temp(temp) 7487 7488 code.putln( 7489 "}") 7490 7491 def generate_function_definitions(self, env, code): 7492 if self.target is not None: 7493 self.target.generate_function_definitions(env, code) 7494 self.body.generate_function_definitions(env, code) 7495 7496 def annotate(self, code): 7497 if self.pattern: 7498 for pattern in self.pattern: 7499 pattern.annotate(code) 7500 if self.target: 7501 self.target.annotate(code) 7502 self.body.annotate(code) 7503 7504 7505class TryFinallyStatNode(StatNode): 7506 # try ... finally statement 7507 # 7508 # body StatNode 7509 # finally_clause StatNode 7510 # finally_except_clause deep-copy of finally_clause for exception case 7511 # in_generator inside of generator => must store away current exception also in return case 7512 # 7513 # Each of the continue, break, return and error gotos runs 7514 # into its own deep-copy of the finally block code. 7515 # In addition, if we're doing an error, we save the 7516 # exception on entry to the finally block and restore 7517 # it on exit. 7518 7519 child_attrs = ["body", "finally_clause", "finally_except_clause"] 7520 7521 preserve_exception = 1 7522 7523 # handle exception case, in addition to return/break/continue 7524 handle_error_case = True 7525 func_return_type = None 7526 finally_except_clause = None 7527 7528 is_try_finally_in_nogil = False 7529 in_generator = False 7530 7531 @staticmethod 7532 def create_analysed(pos, env, body, finally_clause): 7533 node = TryFinallyStatNode(pos, body=body, finally_clause=finally_clause) 7534 return node 7535 7536 def analyse_declarations(self, env): 7537 self.body.analyse_declarations(env) 7538 self.finally_except_clause = copy.deepcopy(self.finally_clause) 7539 self.finally_except_clause.analyse_declarations(env) 7540 self.finally_clause.analyse_declarations(env) 7541 7542 def analyse_expressions(self, env): 7543 self.body = self.body.analyse_expressions(env) 7544 self.finally_clause = self.finally_clause.analyse_expressions(env) 7545 self.finally_except_clause = self.finally_except_clause.analyse_expressions(env) 7546 if env.return_type and not env.return_type.is_void: 7547 self.func_return_type = env.return_type 7548 return self 7549 7550 nogil_check = Node.gil_error 7551 gil_message = "Try-finally statement" 7552 7553 def generate_execution_code(self, code): 7554 code.mark_pos(self.pos) # before changing the error label, in case of tracing errors 7555 code.putln("/*try:*/ {") 7556 7557 old_error_label = code.error_label 7558 old_labels = code.all_new_labels() 7559 new_labels = code.get_all_labels() 7560 new_error_label = code.error_label 7561 if not self.handle_error_case: 7562 code.error_label = old_error_label 7563 catch_label = code.new_label() 7564 7565 was_in_try_finally = code.funcstate.in_try_finally 7566 code.funcstate.in_try_finally = 1 7567 7568 self.body.generate_execution_code(code) 7569 7570 code.funcstate.in_try_finally = was_in_try_finally 7571 code.putln("}") 7572 7573 temps_to_clean_up = code.funcstate.all_free_managed_temps() 7574 code.mark_pos(self.finally_clause.pos) 7575 code.putln("/*finally:*/ {") 7576 7577 # Reset labels only after writing out a potential line trace call for correct nogil error handling. 7578 code.set_all_labels(old_labels) 7579 7580 def fresh_finally_clause(_next=[self.finally_clause]): 7581 # generate the original subtree once and always keep a fresh copy 7582 node = _next[0] 7583 node_copy = copy.deepcopy(node) 7584 if node is self.finally_clause: 7585 _next[0] = node_copy 7586 else: 7587 node = node_copy 7588 return node 7589 7590 preserve_error = self.preserve_exception and code.label_used(new_error_label) 7591 needs_success_cleanup = not self.finally_clause.is_terminator 7592 7593 if not self.body.is_terminator: 7594 code.putln('/*normal exit:*/{') 7595 fresh_finally_clause().generate_execution_code(code) 7596 if not self.finally_clause.is_terminator: 7597 code.put_goto(catch_label) 7598 code.putln('}') 7599 7600 if preserve_error: 7601 code.put_label(new_error_label) 7602 code.putln('/*exception exit:*/{') 7603 if not self.in_generator: 7604 code.putln("__Pyx_PyThreadState_declare") 7605 if self.is_try_finally_in_nogil: 7606 code.declare_gilstate() 7607 if needs_success_cleanup: 7608 exc_lineno_cnames = tuple([ 7609 code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) 7610 for _ in range(2)]) 7611 exc_filename_cname = code.funcstate.allocate_temp( 7612 PyrexTypes.CPtrType(PyrexTypes.c_const_type(PyrexTypes.c_char_type)), 7613 manage_ref=False) 7614 else: 7615 exc_lineno_cnames = exc_filename_cname = None 7616 exc_vars = tuple([ 7617 code.funcstate.allocate_temp(py_object_type, manage_ref=False) 7618 for _ in range(6)]) 7619 self.put_error_catcher( 7620 code, temps_to_clean_up, exc_vars, exc_lineno_cnames, exc_filename_cname) 7621 finally_old_labels = code.all_new_labels() 7622 7623 code.putln('{') 7624 old_exc_vars = code.funcstate.exc_vars 7625 code.funcstate.exc_vars = exc_vars[:3] 7626 self.finally_except_clause.generate_execution_code(code) 7627 code.funcstate.exc_vars = old_exc_vars 7628 code.putln('}') 7629 7630 if needs_success_cleanup: 7631 self.put_error_uncatcher(code, exc_vars, exc_lineno_cnames, exc_filename_cname) 7632 if exc_lineno_cnames: 7633 for cname in exc_lineno_cnames: 7634 code.funcstate.release_temp(cname) 7635 if exc_filename_cname: 7636 code.funcstate.release_temp(exc_filename_cname) 7637 code.put_goto(old_error_label) 7638 7639 for new_label, old_label in zip(code.get_all_labels(), finally_old_labels): 7640 if not code.label_used(new_label): 7641 continue 7642 code.put_label(new_label) 7643 self.put_error_cleaner(code, exc_vars) 7644 code.put_goto(old_label) 7645 7646 for cname in exc_vars: 7647 code.funcstate.release_temp(cname) 7648 code.putln('}') 7649 7650 code.set_all_labels(old_labels) 7651 return_label = code.return_label 7652 exc_vars = () 7653 7654 for i, (new_label, old_label) in enumerate(zip(new_labels, old_labels)): 7655 if not code.label_used(new_label): 7656 continue 7657 if new_label == new_error_label and preserve_error: 7658 continue # handled above 7659 7660 code.putln('%s: {' % new_label) 7661 ret_temp = None 7662 if old_label == return_label: 7663 # return actually raises an (uncatchable) exception in generators that we must preserve 7664 if self.in_generator: 7665 exc_vars = tuple([ 7666 code.funcstate.allocate_temp(py_object_type, manage_ref=False) 7667 for _ in range(6)]) 7668 self.put_error_catcher(code, [], exc_vars) 7669 if not self.finally_clause.is_terminator: 7670 # store away return value for later reuse 7671 if (self.func_return_type and 7672 not self.is_try_finally_in_nogil and 7673 not isinstance(self.finally_clause, GILExitNode)): 7674 ret_temp = code.funcstate.allocate_temp( 7675 self.func_return_type, manage_ref=False) 7676 code.putln("%s = %s;" % (ret_temp, Naming.retval_cname)) 7677 if self.func_return_type.is_pyobject: 7678 code.putln("%s = 0;" % Naming.retval_cname) 7679 7680 fresh_finally_clause().generate_execution_code(code) 7681 7682 if old_label == return_label: 7683 if ret_temp: 7684 code.putln("%s = %s;" % (Naming.retval_cname, ret_temp)) 7685 if self.func_return_type.is_pyobject: 7686 code.putln("%s = 0;" % ret_temp) 7687 code.funcstate.release_temp(ret_temp) 7688 if self.in_generator: 7689 self.put_error_uncatcher(code, exc_vars) 7690 for cname in exc_vars: 7691 code.funcstate.release_temp(cname) 7692 7693 if not self.finally_clause.is_terminator: 7694 code.put_goto(old_label) 7695 code.putln('}') 7696 7697 # End finally 7698 code.put_label(catch_label) 7699 code.putln( 7700 "}") 7701 7702 def generate_function_definitions(self, env, code): 7703 self.body.generate_function_definitions(env, code) 7704 self.finally_clause.generate_function_definitions(env, code) 7705 7706 def put_error_catcher(self, code, temps_to_clean_up, exc_vars, 7707 exc_lineno_cnames=None, exc_filename_cname=None): 7708 code.globalstate.use_utility_code(restore_exception_utility_code) 7709 code.globalstate.use_utility_code(get_exception_utility_code) 7710 code.globalstate.use_utility_code(swap_exception_utility_code) 7711 7712 if self.is_try_finally_in_nogil: 7713 code.put_ensure_gil(declare_gilstate=False) 7714 code.putln("__Pyx_PyThreadState_assign") 7715 7716 code.putln(' '.join(["%s = 0;" % var for var in exc_vars])) 7717 for temp_name, type in temps_to_clean_up: 7718 code.put_xdecref_clear(temp_name, type) 7719 7720 # not using preprocessor here to avoid warnings about 7721 # unused utility functions and/or temps 7722 code.putln("if (PY_MAJOR_VERSION >= 3)" 7723 " __Pyx_ExceptionSwap(&%s, &%s, &%s);" % exc_vars[3:]) 7724 code.putln("if ((PY_MAJOR_VERSION < 3) ||" 7725 # if __Pyx_GetException() fails in Py3, 7726 # store the newly raised exception instead 7727 " unlikely(__Pyx_GetException(&%s, &%s, &%s) < 0)) " 7728 "__Pyx_ErrFetch(&%s, &%s, &%s);" % (exc_vars[:3] * 2)) 7729 for var in exc_vars: 7730 code.put_xgotref(var) 7731 if exc_lineno_cnames: 7732 code.putln("%s = %s; %s = %s; %s = %s;" % ( 7733 exc_lineno_cnames[0], Naming.lineno_cname, 7734 exc_lineno_cnames[1], Naming.clineno_cname, 7735 exc_filename_cname, Naming.filename_cname)) 7736 7737 if self.is_try_finally_in_nogil: 7738 code.put_release_ensured_gil() 7739 7740 def put_error_uncatcher(self, code, exc_vars, exc_lineno_cnames=None, exc_filename_cname=None): 7741 code.globalstate.use_utility_code(restore_exception_utility_code) 7742 code.globalstate.use_utility_code(reset_exception_utility_code) 7743 7744 if self.is_try_finally_in_nogil: 7745 code.put_ensure_gil(declare_gilstate=False) 7746 7747 # not using preprocessor here to avoid warnings about 7748 # unused utility functions and/or temps 7749 code.putln("if (PY_MAJOR_VERSION >= 3) {") 7750 for var in exc_vars[3:]: 7751 code.put_xgiveref(var) 7752 code.putln("__Pyx_ExceptionReset(%s, %s, %s);" % exc_vars[3:]) 7753 code.putln("}") 7754 for var in exc_vars[:3]: 7755 code.put_xgiveref(var) 7756 code.putln("__Pyx_ErrRestore(%s, %s, %s);" % exc_vars[:3]) 7757 7758 if self.is_try_finally_in_nogil: 7759 code.put_release_ensured_gil() 7760 7761 code.putln(' '.join(["%s = 0;" % var for var in exc_vars])) 7762 if exc_lineno_cnames: 7763 code.putln("%s = %s; %s = %s; %s = %s;" % ( 7764 Naming.lineno_cname, exc_lineno_cnames[0], 7765 Naming.clineno_cname, exc_lineno_cnames[1], 7766 Naming.filename_cname, exc_filename_cname)) 7767 7768 def put_error_cleaner(self, code, exc_vars): 7769 code.globalstate.use_utility_code(reset_exception_utility_code) 7770 if self.is_try_finally_in_nogil: 7771 code.put_ensure_gil(declare_gilstate=False) 7772 7773 # not using preprocessor here to avoid warnings about 7774 # unused utility functions and/or temps 7775 code.putln("if (PY_MAJOR_VERSION >= 3) {") 7776 for var in exc_vars[3:]: 7777 code.put_xgiveref(var) 7778 code.putln("__Pyx_ExceptionReset(%s, %s, %s);" % exc_vars[3:]) 7779 code.putln("}") 7780 for var in exc_vars[:3]: 7781 code.put_xdecref_clear(var, py_object_type) 7782 if self.is_try_finally_in_nogil: 7783 code.put_release_ensured_gil() 7784 code.putln(' '.join(["%s = 0;"]*3) % exc_vars[3:]) 7785 7786 def annotate(self, code): 7787 self.body.annotate(code) 7788 self.finally_clause.annotate(code) 7789 7790 7791class NogilTryFinallyStatNode(TryFinallyStatNode): 7792 """ 7793 A try/finally statement that may be used in nogil code sections. 7794 """ 7795 7796 preserve_exception = False 7797 nogil_check = None 7798 7799 7800class GILStatNode(NogilTryFinallyStatNode): 7801 # 'with gil' or 'with nogil' statement 7802 # 7803 # state string 'gil' or 'nogil' 7804 7805 state_temp = None 7806 7807 def __init__(self, pos, state, body): 7808 self.state = state 7809 self.create_state_temp_if_needed(pos, state, body) 7810 TryFinallyStatNode.__init__( 7811 self, pos, 7812 body=body, 7813 finally_clause=GILExitNode( 7814 pos, state=state, state_temp=self.state_temp)) 7815 7816 def create_state_temp_if_needed(self, pos, state, body): 7817 from .ParseTreeTransforms import YieldNodeCollector 7818 collector = YieldNodeCollector() 7819 collector.visitchildren(body) 7820 if not collector.yields: 7821 return 7822 7823 if state == 'gil': 7824 temp_type = PyrexTypes.c_gilstate_type 7825 else: 7826 temp_type = PyrexTypes.c_threadstate_ptr_type 7827 from . import ExprNodes 7828 self.state_temp = ExprNodes.TempNode(pos, temp_type) 7829 7830 def analyse_declarations(self, env): 7831 env._in_with_gil_block = (self.state == 'gil') 7832 if self.state == 'gil': 7833 env.has_with_gil_block = True 7834 7835 return super(GILStatNode, self).analyse_declarations(env) 7836 7837 def analyse_expressions(self, env): 7838 env.use_utility_code( 7839 UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c")) 7840 was_nogil = env.nogil 7841 env.nogil = self.state == 'nogil' 7842 node = TryFinallyStatNode.analyse_expressions(self, env) 7843 env.nogil = was_nogil 7844 return node 7845 7846 def generate_execution_code(self, code): 7847 code.mark_pos(self.pos) 7848 code.begin_block() 7849 if self.state_temp: 7850 self.state_temp.allocate(code) 7851 variable = self.state_temp.result() 7852 else: 7853 variable = None 7854 7855 old_gil_config = code.funcstate.gil_owned 7856 if self.state == 'gil': 7857 code.put_ensure_gil(variable=variable) 7858 code.funcstate.gil_owned = True 7859 else: 7860 code.put_release_gil(variable=variable) 7861 code.funcstate.gil_owned = False 7862 7863 TryFinallyStatNode.generate_execution_code(self, code) 7864 7865 if self.state_temp: 7866 self.state_temp.release(code) 7867 7868 code.funcstate.gil_owned = old_gil_config 7869 code.end_block() 7870 7871 7872class GILExitNode(StatNode): 7873 """ 7874 Used as the 'finally' block in a GILStatNode 7875 7876 state string 'gil' or 'nogil' 7877 """ 7878 7879 child_attrs = [] 7880 state_temp = None 7881 7882 def analyse_expressions(self, env): 7883 return self 7884 7885 def generate_execution_code(self, code): 7886 if self.state_temp: 7887 variable = self.state_temp.result() 7888 else: 7889 variable = None 7890 7891 if self.state == 'gil': 7892 code.put_release_ensured_gil(variable) 7893 else: 7894 code.put_acquire_gil(variable) 7895 7896 7897class EnsureGILNode(GILExitNode): 7898 """ 7899 Ensure the GIL in nogil functions for cleanup before returning. 7900 """ 7901 7902 def generate_execution_code(self, code): 7903 code.put_ensure_gil(declare_gilstate=False) 7904 7905 7906def cython_view_utility_code(): 7907 from . import MemoryView 7908 return MemoryView.view_utility_code 7909 7910 7911utility_code_for_cimports = { 7912 # utility code (or inlining c) in a pxd (or pyx) file. 7913 # TODO: Consider a generic user-level mechanism for importing 7914 'cpython.array' : lambda : UtilityCode.load_cached("ArrayAPI", "arrayarray.h"), 7915 'cpython.array.array' : lambda : UtilityCode.load_cached("ArrayAPI", "arrayarray.h"), 7916 'cython.view' : cython_view_utility_code, 7917} 7918 7919utility_code_for_imports = { 7920 # utility code used when special modules are imported. 7921 # TODO: Consider a generic user-level mechanism for importing 7922 'asyncio': ("__Pyx_patch_asyncio", "PatchAsyncIO", "Coroutine.c"), 7923 'inspect': ("__Pyx_patch_inspect", "PatchInspect", "Coroutine.c"), 7924} 7925 7926 7927class CImportStatNode(StatNode): 7928 # cimport statement 7929 # 7930 # module_name string Qualified name of module being imported 7931 # as_name string or None Name specified in "as" clause, if any 7932 # is_absolute bool True for absolute imports, False otherwise 7933 7934 child_attrs = [] 7935 is_absolute = False 7936 7937 def analyse_declarations(self, env): 7938 if not env.is_module_scope: 7939 error(self.pos, "cimport only allowed at module level") 7940 return 7941 module_scope = env.find_module( 7942 self.module_name, self.pos, relative_level=0 if self.is_absolute else -1) 7943 if "." in self.module_name: 7944 names = [EncodedString(name) for name in self.module_name.split(".")] 7945 top_name = names[0] 7946 top_module_scope = env.context.find_submodule(top_name) 7947 module_scope = top_module_scope 7948 for name in names[1:]: 7949 submodule_scope = module_scope.find_submodule(name) 7950 module_scope.declare_module(name, submodule_scope, self.pos) 7951 module_scope = submodule_scope 7952 if self.as_name: 7953 env.declare_module(self.as_name, module_scope, self.pos) 7954 else: 7955 env.add_imported_module(module_scope) 7956 env.declare_module(top_name, top_module_scope, self.pos) 7957 else: 7958 name = self.as_name or self.module_name 7959 env.declare_module(name, module_scope, self.pos) 7960 if self.module_name in utility_code_for_cimports: 7961 env.use_utility_code(utility_code_for_cimports[self.module_name]()) 7962 7963 def analyse_expressions(self, env): 7964 return self 7965 7966 def generate_execution_code(self, code): 7967 pass 7968 7969 7970class FromCImportStatNode(StatNode): 7971 # from ... cimport statement 7972 # 7973 # module_name string Qualified name of module 7974 # relative_level int or None Relative import: number of dots before module_name 7975 # imported_names [(pos, name, as_name, kind)] Names to be imported 7976 7977 child_attrs = [] 7978 module_name = None 7979 relative_level = None 7980 imported_names = None 7981 7982 def analyse_declarations(self, env): 7983 if not env.is_module_scope: 7984 error(self.pos, "cimport only allowed at module level") 7985 return 7986 if self.relative_level and self.relative_level > env.qualified_name.count('.'): 7987 error(self.pos, "relative cimport beyond main package is not allowed") 7988 return 7989 module_scope = env.find_module(self.module_name, self.pos, relative_level=self.relative_level) 7990 module_name = module_scope.qualified_name 7991 env.add_imported_module(module_scope) 7992 for pos, name, as_name, kind in self.imported_names: 7993 if name == "*": 7994 for local_name, entry in list(module_scope.entries.items()): 7995 env.add_imported_entry(local_name, entry, pos) 7996 else: 7997 entry = module_scope.lookup(name) 7998 if entry: 7999 if kind and not self.declaration_matches(entry, kind): 8000 entry.redeclared(pos) 8001 entry.used = 1 8002 else: 8003 if kind == 'struct' or kind == 'union': 8004 entry = module_scope.declare_struct_or_union( 8005 name, kind=kind, scope=None, typedef_flag=0, pos=pos) 8006 elif kind == 'class': 8007 entry = module_scope.declare_c_class(name, pos=pos, module_name=module_name) 8008 else: 8009 submodule_scope = env.context.find_module( 8010 name, relative_to=module_scope, pos=self.pos, absolute_fallback=False) 8011 if submodule_scope.parent_module is module_scope: 8012 env.declare_module(as_name or name, submodule_scope, self.pos) 8013 else: 8014 error(pos, "Name '%s' not declared in module '%s'" % (name, module_name)) 8015 8016 if entry: 8017 local_name = as_name or name 8018 env.add_imported_entry(local_name, entry, pos) 8019 8020 if module_name.startswith('cpython') or module_name.startswith('cython'): # enough for now 8021 if module_name in utility_code_for_cimports: 8022 env.use_utility_code(utility_code_for_cimports[module_name]()) 8023 for _, name, _, _ in self.imported_names: 8024 fqname = '%s.%s' % (module_name, name) 8025 if fqname in utility_code_for_cimports: 8026 env.use_utility_code(utility_code_for_cimports[fqname]()) 8027 8028 def declaration_matches(self, entry, kind): 8029 if not entry.is_type: 8030 return 0 8031 type = entry.type 8032 if kind == 'class': 8033 if not type.is_extension_type: 8034 return 0 8035 else: 8036 if not type.is_struct_or_union: 8037 return 0 8038 if kind != type.kind: 8039 return 0 8040 return 1 8041 8042 def analyse_expressions(self, env): 8043 return self 8044 8045 def generate_execution_code(self, code): 8046 pass 8047 8048 8049class FromImportStatNode(StatNode): 8050 # from ... import statement 8051 # 8052 # module ImportNode 8053 # items [(string, NameNode)] 8054 # interned_items [(string, NameNode, ExprNode)] 8055 # item PyTempNode used internally 8056 # import_star boolean used internally 8057 8058 child_attrs = ["module"] 8059 import_star = 0 8060 8061 def analyse_declarations(self, env): 8062 for name, target in self.items: 8063 if name == "*": 8064 if not env.is_module_scope: 8065 error(self.pos, "import * only allowed at module level") 8066 return 8067 env.has_import_star = 1 8068 self.import_star = 1 8069 else: 8070 target.analyse_target_declaration(env) 8071 8072 def analyse_expressions(self, env): 8073 from . import ExprNodes 8074 self.module = self.module.analyse_expressions(env) 8075 self.item = ExprNodes.RawCNameExprNode(self.pos, py_object_type) 8076 self.interned_items = [] 8077 for name, target in self.items: 8078 if name == '*': 8079 for _, entry in env.entries.items(): 8080 if not entry.is_type and entry.type.is_extension_type: 8081 env.use_utility_code(UtilityCode.load_cached("ExtTypeTest", "ObjectHandling.c")) 8082 break 8083 else: 8084 entry = env.lookup(target.name) 8085 # check whether or not entry is already cimported 8086 if (entry.is_type and entry.type.name == name 8087 and hasattr(entry.type, 'module_name')): 8088 if entry.type.module_name == self.module.module_name.value: 8089 # cimported with absolute name 8090 continue 8091 try: 8092 # cimported with relative name 8093 module = env.find_module(self.module.module_name.value, pos=self.pos, 8094 relative_level=self.module.level) 8095 if entry.type.module_name == module.qualified_name: 8096 continue 8097 except AttributeError: 8098 pass 8099 target = target.analyse_target_expression(env, None) # FIXME? 8100 if target.type is py_object_type: 8101 coerced_item = None 8102 else: 8103 coerced_item = self.item.coerce_to(target.type, env) 8104 self.interned_items.append((name, target, coerced_item)) 8105 return self 8106 8107 def generate_execution_code(self, code): 8108 code.mark_pos(self.pos) 8109 self.module.generate_evaluation_code(code) 8110 if self.import_star: 8111 code.putln( 8112 'if (%s(%s) < 0) %s;' % ( 8113 Naming.import_star, 8114 self.module.py_result(), 8115 code.error_goto(self.pos))) 8116 item_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True) 8117 self.item.set_cname(item_temp) 8118 if self.interned_items: 8119 code.globalstate.use_utility_code( 8120 UtilityCode.load_cached("ImportFrom", "ImportExport.c")) 8121 for name, target, coerced_item in self.interned_items: 8122 code.putln( 8123 '%s = __Pyx_ImportFrom(%s, %s); %s' % ( 8124 item_temp, 8125 self.module.py_result(), 8126 code.intern_identifier(name), 8127 code.error_goto_if_null(item_temp, self.pos))) 8128 code.put_gotref(item_temp) 8129 if coerced_item is None: 8130 target.generate_assignment_code(self.item, code) 8131 else: 8132 coerced_item.allocate_temp_result(code) 8133 coerced_item.generate_result_code(code) 8134 target.generate_assignment_code(coerced_item, code) 8135 code.put_decref_clear(item_temp, py_object_type) 8136 code.funcstate.release_temp(item_temp) 8137 self.module.generate_disposal_code(code) 8138 self.module.free_temps(code) 8139 8140 8141class ParallelNode(Node): 8142 """ 8143 Base class for cython.parallel constructs. 8144 """ 8145 8146 nogil_check = None 8147 8148 8149class ParallelStatNode(StatNode, ParallelNode): 8150 """ 8151 Base class for 'with cython.parallel.parallel():' and 'for i in prange():'. 8152 8153 assignments { Entry(var) : (var.pos, inplace_operator_or_None) } 8154 assignments to variables in this parallel section 8155 8156 parent parent ParallelStatNode or None 8157 is_parallel indicates whether this node is OpenMP parallel 8158 (true for #pragma omp parallel for and 8159 #pragma omp parallel) 8160 8161 is_parallel is true for: 8162 8163 #pragma omp parallel 8164 #pragma omp parallel for 8165 8166 sections, but NOT for 8167 8168 #pragma omp for 8169 8170 We need this to determine the sharing attributes. 8171 8172 privatization_insertion_point a code insertion point used to make temps 8173 private (esp. the "nsteps" temp) 8174 8175 args tuple the arguments passed to the parallel construct 8176 kwargs DictNode the keyword arguments passed to the parallel 8177 construct (replaced by its compile time value) 8178 """ 8179 8180 child_attrs = ['body', 'num_threads'] 8181 8182 body = None 8183 8184 is_prange = False 8185 is_nested_prange = False 8186 8187 error_label_used = False 8188 8189 num_threads = None 8190 chunksize = None 8191 8192 parallel_exc = ( 8193 Naming.parallel_exc_type, 8194 Naming.parallel_exc_value, 8195 Naming.parallel_exc_tb, 8196 ) 8197 8198 parallel_pos_info = ( 8199 Naming.parallel_filename, 8200 Naming.parallel_lineno, 8201 Naming.parallel_clineno, 8202 ) 8203 8204 pos_info = ( 8205 Naming.filename_cname, 8206 Naming.lineno_cname, 8207 Naming.clineno_cname, 8208 ) 8209 8210 critical_section_counter = 0 8211 8212 def __init__(self, pos, **kwargs): 8213 super(ParallelStatNode, self).__init__(pos, **kwargs) 8214 8215 # All assignments in this scope 8216 self.assignments = kwargs.get('assignments') or {} 8217 8218 # All seen closure cnames and their temporary cnames 8219 self.seen_closure_vars = set() 8220 8221 # Dict of variables that should be declared (first|last|)private or 8222 # reduction { Entry: (op, lastprivate) }. 8223 # If op is not None, it's a reduction. 8224 self.privates = {} 8225 8226 # [NameNode] 8227 self.assigned_nodes = [] 8228 8229 def analyse_declarations(self, env): 8230 self.body.analyse_declarations(env) 8231 8232 self.num_threads = None 8233 8234 if self.kwargs: 8235 # Try to find num_threads and chunksize keyword arguments 8236 pairs = [] 8237 seen = set() 8238 for dictitem in self.kwargs.key_value_pairs: 8239 if dictitem.key.value in seen: 8240 error(self.pos, "Duplicate keyword argument found: %s" % dictitem.key.value) 8241 seen.add(dictitem.key.value) 8242 if dictitem.key.value == 'num_threads': 8243 if not dictitem.value.is_none: 8244 self.num_threads = dictitem.value 8245 elif self.is_prange and dictitem.key.value == 'chunksize': 8246 if not dictitem.value.is_none: 8247 self.chunksize = dictitem.value 8248 else: 8249 pairs.append(dictitem) 8250 8251 self.kwargs.key_value_pairs = pairs 8252 8253 try: 8254 self.kwargs = self.kwargs.compile_time_value(env) 8255 except Exception as e: 8256 error(self.kwargs.pos, "Only compile-time values may be " 8257 "supplied as keyword arguments") 8258 else: 8259 self.kwargs = {} 8260 8261 for kw, val in self.kwargs.items(): 8262 if kw not in self.valid_keyword_arguments: 8263 error(self.pos, "Invalid keyword argument: %s" % kw) 8264 else: 8265 setattr(self, kw, val) 8266 8267 def analyse_expressions(self, env): 8268 if self.num_threads: 8269 self.num_threads = self.num_threads.analyse_expressions(env) 8270 8271 if self.chunksize: 8272 self.chunksize = self.chunksize.analyse_expressions(env) 8273 8274 self.body = self.body.analyse_expressions(env) 8275 self.analyse_sharing_attributes(env) 8276 8277 if self.num_threads is not None: 8278 if self.parent and self.parent.num_threads is not None and not self.parent.is_prange: 8279 error(self.pos, "num_threads already declared in outer section") 8280 elif self.parent and not self.parent.is_prange: 8281 error(self.pos, "num_threads must be declared in the parent parallel section") 8282 elif (self.num_threads.type.is_int and 8283 self.num_threads.is_literal and 8284 self.num_threads.compile_time_value(env) <= 0): 8285 error(self.pos, "argument to num_threads must be greater than 0") 8286 8287 if not self.num_threads.is_simple() or self.num_threads.type.is_pyobject: 8288 self.num_threads = self.num_threads.coerce_to( 8289 PyrexTypes.c_int_type, env).coerce_to_temp(env) 8290 return self 8291 8292 def analyse_sharing_attributes(self, env): 8293 """ 8294 Analyse the privates for this block and set them in self.privates. 8295 This should be called in a post-order fashion during the 8296 analyse_expressions phase 8297 """ 8298 for entry, (pos, op) in self.assignments.items(): 8299 8300 if self.is_prange and not self.is_parallel: 8301 # closely nested prange in a with parallel block, disallow 8302 # assigning to privates in the with parallel block (we 8303 # consider it too implicit and magicky for users) 8304 if entry in self.parent.assignments: 8305 error(pos, "Cannot assign to private of outer parallel block") 8306 continue 8307 8308 if not self.is_prange and op: 8309 # Again possible, but considered to magicky 8310 error(pos, "Reductions not allowed for parallel blocks") 8311 continue 8312 8313 # By default all variables should have the same values as if 8314 # executed sequentially 8315 lastprivate = True 8316 self.propagate_var_privatization(entry, pos, op, lastprivate) 8317 8318 def propagate_var_privatization(self, entry, pos, op, lastprivate): 8319 """ 8320 Propagate the sharing attributes of a variable. If the privatization is 8321 determined by a parent scope, done propagate further. 8322 8323 If we are a prange, we propagate our sharing attributes outwards to 8324 other pranges. If we are a prange in parallel block and the parallel 8325 block does not determine the variable private, we propagate to the 8326 parent of the parent. Recursion stops at parallel blocks, as they have 8327 no concept of lastprivate or reduction. 8328 8329 So the following cases propagate: 8330 8331 sum is a reduction for all loops: 8332 8333 for i in prange(n): 8334 for j in prange(n): 8335 for k in prange(n): 8336 sum += i * j * k 8337 8338 sum is a reduction for both loops, local_var is private to the 8339 parallel with block: 8340 8341 for i in prange(n): 8342 with parallel: 8343 local_var = ... # private to the parallel 8344 for j in prange(n): 8345 sum += i * j 8346 8347 Nested with parallel blocks are disallowed, because they wouldn't 8348 allow you to propagate lastprivates or reductions: 8349 8350 #pragma omp parallel for lastprivate(i) 8351 for i in prange(n): 8352 8353 sum = 0 8354 8355 #pragma omp parallel private(j, sum) 8356 with parallel: 8357 8358 #pragma omp parallel 8359 with parallel: 8360 8361 #pragma omp for lastprivate(j) reduction(+:sum) 8362 for j in prange(n): 8363 sum += i 8364 8365 # sum and j are well-defined here 8366 8367 # sum and j are undefined here 8368 8369 # sum and j are undefined here 8370 """ 8371 self.privates[entry] = (op, lastprivate) 8372 8373 if entry.type.is_memoryviewslice: 8374 error(pos, "Memoryview slices can only be shared in parallel sections") 8375 return 8376 8377 if self.is_prange: 8378 if not self.is_parallel and entry not in self.parent.assignments: 8379 # Parent is a parallel with block 8380 parent = self.parent.parent 8381 else: 8382 parent = self.parent 8383 8384 # We don't need to propagate privates, only reductions and 8385 # lastprivates 8386 if parent and (op or lastprivate): 8387 parent.propagate_var_privatization(entry, pos, op, lastprivate) 8388 8389 def _allocate_closure_temp(self, code, entry): 8390 """ 8391 Helper function that allocate a temporary for a closure variable that 8392 is assigned to. 8393 """ 8394 if self.parent: 8395 return self.parent._allocate_closure_temp(code, entry) 8396 8397 if entry.cname in self.seen_closure_vars: 8398 return entry.cname 8399 8400 cname = code.funcstate.allocate_temp(entry.type, True) 8401 8402 # Add both the actual cname and the temp cname, as the actual cname 8403 # will be replaced with the temp cname on the entry 8404 self.seen_closure_vars.add(entry.cname) 8405 self.seen_closure_vars.add(cname) 8406 8407 self.modified_entries.append((entry, entry.cname)) 8408 code.putln("%s = %s;" % (cname, entry.cname)) 8409 entry.cname = cname 8410 8411 def initialize_privates_to_nan(self, code, exclude=None): 8412 first = True 8413 8414 for entry, (op, lastprivate) in sorted(self.privates.items()): 8415 if not op and (not exclude or entry != exclude): 8416 invalid_value = entry.type.invalid_value() 8417 8418 if invalid_value: 8419 if first: 8420 code.putln("/* Initialize private variables to " 8421 "invalid values */") 8422 first = False 8423 code.putln("%s = %s;" % (entry.cname, 8424 entry.type.cast_code(invalid_value))) 8425 8426 def evaluate_before_block(self, code, expr): 8427 c = self.begin_of_parallel_control_block_point_after_decls 8428 # we need to set the owner to ourselves temporarily, as 8429 # allocate_temp may generate a comment in the middle of our pragma 8430 # otherwise when DebugFlags.debug_temp_code_comments is in effect 8431 owner = c.funcstate.owner 8432 c.funcstate.owner = c 8433 expr.generate_evaluation_code(c) 8434 c.funcstate.owner = owner 8435 8436 return expr.result() 8437 8438 def put_num_threads(self, code): 8439 """ 8440 Write self.num_threads if set as the num_threads OpenMP directive 8441 """ 8442 if self.num_threads is not None: 8443 code.put(" num_threads(%s)" % self.evaluate_before_block(code, self.num_threads)) 8444 8445 8446 def declare_closure_privates(self, code): 8447 """ 8448 If a variable is in a scope object, we need to allocate a temp and 8449 assign the value from the temp to the variable in the scope object 8450 after the parallel section. This kind of copying should be done only 8451 in the outermost parallel section. 8452 """ 8453 self.modified_entries = [] 8454 8455 for entry in sorted(self.assignments): 8456 if entry.from_closure or entry.in_closure: 8457 self._allocate_closure_temp(code, entry) 8458 8459 def release_closure_privates(self, code): 8460 """ 8461 Release any temps used for variables in scope objects. As this is the 8462 outermost parallel block, we don't need to delete the cnames from 8463 self.seen_closure_vars. 8464 """ 8465 for entry, original_cname in self.modified_entries: 8466 code.putln("%s = %s;" % (original_cname, entry.cname)) 8467 code.funcstate.release_temp(entry.cname) 8468 entry.cname = original_cname 8469 8470 def privatize_temps(self, code, exclude_temps=()): 8471 """ 8472 Make any used temporaries private. Before the relevant code block 8473 code.start_collecting_temps() should have been called. 8474 """ 8475 c = self.privatization_insertion_point 8476 self.privatization_insertion_point = None 8477 8478 if self.is_parallel: 8479 self.temps = temps = code.funcstate.stop_collecting_temps() 8480 privates, firstprivates = [], [] 8481 for temp, type in sorted(temps): 8482 if type.is_pyobject or type.is_memoryviewslice: 8483 firstprivates.append(temp) 8484 else: 8485 privates.append(temp) 8486 8487 if privates: 8488 c.put(" private(%s)" % ", ".join(privates)) 8489 if firstprivates: 8490 c.put(" firstprivate(%s)" % ", ".join(firstprivates)) 8491 8492 if self.breaking_label_used: 8493 shared_vars = [Naming.parallel_why] 8494 if self.error_label_used: 8495 shared_vars.extend(self.parallel_exc) 8496 c.put(" private(%s, %s, %s)" % self.pos_info) 8497 8498 c.put(" shared(%s)" % ', '.join(shared_vars)) 8499 8500 def cleanup_temps(self, code): 8501 # Now clean up any memoryview slice and object temporaries 8502 if self.is_parallel and not self.is_nested_prange: 8503 code.putln("/* Clean up any temporaries */") 8504 for temp, type in sorted(self.temps): 8505 if type.is_memoryviewslice: 8506 code.put_xdecref_memoryviewslice(temp, have_gil=False) 8507 elif type.is_pyobject: 8508 code.put_xdecref(temp, type) 8509 code.putln("%s = NULL;" % temp) 8510 8511 def setup_parallel_control_flow_block(self, code): 8512 """ 8513 Sets up a block that surrounds the parallel block to determine 8514 how the parallel section was exited. Any kind of return is 8515 trapped (break, continue, return, exceptions). This is the idea: 8516 8517 { 8518 int why = 0; 8519 8520 #pragma omp parallel 8521 { 8522 return # -> goto new_return_label; 8523 goto end_parallel; 8524 8525 new_return_label: 8526 why = 3; 8527 goto end_parallel; 8528 8529 end_parallel:; 8530 #pragma omp flush(why) # we need to flush for every iteration 8531 } 8532 8533 if (why == 3) 8534 goto old_return_label; 8535 } 8536 """ 8537 self.old_loop_labels = code.new_loop_labels() 8538 self.old_error_label = code.new_error_label() 8539 self.old_return_label = code.return_label 8540 code.return_label = code.new_label(name="return") 8541 8542 code.begin_block() # parallel control flow block 8543 self.begin_of_parallel_control_block_point = code.insertion_point() 8544 self.begin_of_parallel_control_block_point_after_decls = code.insertion_point() 8545 8546 self.undef_builtin_expect_apple_gcc_bug(code) 8547 8548 def begin_parallel_block(self, code): 8549 """ 8550 Each OpenMP thread in a parallel section that contains a with gil block 8551 must have the thread-state initialized. The call to 8552 PyGILState_Release() then deallocates our threadstate. If we wouldn't 8553 do this, each with gil block would allocate and deallocate one, thereby 8554 losing exception information before it can be saved before leaving the 8555 parallel section. 8556 """ 8557 self.begin_of_parallel_block = code.insertion_point() 8558 8559 def end_parallel_block(self, code): 8560 """ 8561 To ensure all OpenMP threads have thread states, we ensure the GIL 8562 in each thread (which creates a thread state if it doesn't exist), 8563 after which we release the GIL. 8564 On exit, reacquire the GIL and release the thread state. 8565 8566 If compiled without OpenMP support (at the C level), then we still have 8567 to acquire the GIL to decref any object temporaries. 8568 """ 8569 begin_code = self.begin_of_parallel_block 8570 self.begin_of_parallel_block = None 8571 8572 if self.error_label_used: 8573 end_code = code 8574 8575 begin_code.putln("#ifdef _OPENMP") 8576 begin_code.put_ensure_gil(declare_gilstate=True) 8577 begin_code.putln("Py_BEGIN_ALLOW_THREADS") 8578 begin_code.putln("#endif /* _OPENMP */") 8579 8580 end_code.putln("#ifdef _OPENMP") 8581 end_code.putln("Py_END_ALLOW_THREADS") 8582 end_code.putln("#else") 8583 end_code.put_safe("{\n") 8584 end_code.put_ensure_gil() 8585 end_code.putln("#endif /* _OPENMP */") 8586 self.cleanup_temps(end_code) 8587 end_code.put_release_ensured_gil() 8588 end_code.putln("#ifndef _OPENMP") 8589 end_code.put_safe("}\n") 8590 end_code.putln("#endif /* _OPENMP */") 8591 8592 def trap_parallel_exit(self, code, should_flush=False): 8593 """ 8594 Trap any kind of return inside a parallel construct. 'should_flush' 8595 indicates whether the variable should be flushed, which is needed by 8596 prange to skip the loop. It also indicates whether we need to register 8597 a continue (we need this for parallel blocks, but not for prange 8598 loops, as it is a direct jump there). 8599 8600 It uses the same mechanism as try/finally: 8601 1 continue 8602 2 break 8603 3 return 8604 4 error 8605 """ 8606 save_lastprivates_label = code.new_label() 8607 dont_return_label = code.new_label() 8608 8609 self.any_label_used = False 8610 self.breaking_label_used = False 8611 self.error_label_used = False 8612 8613 self.parallel_private_temps = [] 8614 8615 all_labels = code.get_all_labels() 8616 8617 # Figure this out before starting to generate any code 8618 for label in all_labels: 8619 if code.label_used(label): 8620 self.breaking_label_used = (self.breaking_label_used or 8621 label != code.continue_label) 8622 self.any_label_used = True 8623 8624 if self.any_label_used: 8625 code.put_goto(dont_return_label) 8626 8627 for i, label in enumerate(all_labels): 8628 if not code.label_used(label): 8629 continue 8630 8631 is_continue_label = label == code.continue_label 8632 8633 code.put_label(label) 8634 8635 if not (should_flush and is_continue_label): 8636 if label == code.error_label: 8637 self.error_label_used = True 8638 self.fetch_parallel_exception(code) 8639 8640 code.putln("%s = %d;" % (Naming.parallel_why, i + 1)) 8641 8642 if (self.breaking_label_used and self.is_prange and not 8643 is_continue_label): 8644 code.put_goto(save_lastprivates_label) 8645 else: 8646 code.put_goto(dont_return_label) 8647 8648 if self.any_label_used: 8649 if self.is_prange and self.breaking_label_used: 8650 # Don't rely on lastprivate, save our lastprivates 8651 code.put_label(save_lastprivates_label) 8652 self.save_parallel_vars(code) 8653 8654 code.put_label(dont_return_label) 8655 8656 if should_flush and self.breaking_label_used: 8657 code.putln_openmp("#pragma omp flush(%s)" % Naming.parallel_why) 8658 8659 def save_parallel_vars(self, code): 8660 """ 8661 The following shenanigans are instated when we break, return or 8662 propagate errors from a prange. In this case we cannot rely on 8663 lastprivate() to do its job, as no iterations may have executed yet 8664 in the last thread, leaving the values undefined. It is most likely 8665 that the breaking thread has well-defined values of the lastprivate 8666 variables, so we keep those values. 8667 """ 8668 section_name = "__pyx_parallel_lastprivates%d" % self.critical_section_counter 8669 code.putln_openmp("#pragma omp critical(%s)" % section_name) 8670 ParallelStatNode.critical_section_counter += 1 8671 8672 code.begin_block() # begin critical section 8673 8674 c = self.begin_of_parallel_control_block_point 8675 8676 temp_count = 0 8677 for entry, (op, lastprivate) in sorted(self.privates.items()): 8678 if not lastprivate or entry.type.is_pyobject: 8679 continue 8680 8681 type_decl = entry.type.empty_declaration_code() 8682 temp_cname = "__pyx_parallel_temp%d" % temp_count 8683 private_cname = entry.cname 8684 8685 temp_count += 1 8686 8687 invalid_value = entry.type.invalid_value() 8688 if invalid_value: 8689 init = ' = ' + entry.type.cast_code(invalid_value) 8690 else: 8691 init = '' 8692 # Declare the parallel private in the outer block 8693 c.putln("%s %s%s;" % (type_decl, temp_cname, init)) 8694 8695 # Initialize before escaping 8696 code.putln("%s = %s;" % (temp_cname, private_cname)) 8697 8698 self.parallel_private_temps.append((temp_cname, private_cname)) 8699 8700 code.end_block() # end critical section 8701 8702 def fetch_parallel_exception(self, code): 8703 """ 8704 As each OpenMP thread may raise an exception, we need to fetch that 8705 exception from the threadstate and save it for after the parallel 8706 section where it can be re-raised in the master thread. 8707 8708 Although it would seem that __pyx_filename, __pyx_lineno and 8709 __pyx_clineno are only assigned to under exception conditions (i.e., 8710 when we have the GIL), and thus should be allowed to be shared without 8711 any race condition, they are in fact subject to the same race 8712 conditions that they were previously when they were global variables 8713 and functions were allowed to release the GIL: 8714 8715 thread A thread B 8716 acquire 8717 set lineno 8718 release 8719 acquire 8720 set lineno 8721 release 8722 acquire 8723 fetch exception 8724 release 8725 skip the fetch 8726 8727 deallocate threadstate deallocate threadstate 8728 """ 8729 code.begin_block() 8730 code.put_ensure_gil(declare_gilstate=True) 8731 8732 code.putln_openmp("#pragma omp flush(%s)" % Naming.parallel_exc_type) 8733 code.putln( 8734 "if (!%s) {" % Naming.parallel_exc_type) 8735 8736 code.putln("__Pyx_ErrFetchWithState(&%s, &%s, &%s);" % self.parallel_exc) 8737 pos_info = chain(*zip(self.parallel_pos_info, self.pos_info)) 8738 code.funcstate.uses_error_indicator = True 8739 code.putln("%s = %s; %s = %s; %s = %s;" % tuple(pos_info)) 8740 code.put_gotref(Naming.parallel_exc_type) 8741 8742 code.putln( 8743 "}") 8744 8745 code.put_release_ensured_gil() 8746 code.end_block() 8747 8748 def restore_parallel_exception(self, code): 8749 "Re-raise a parallel exception" 8750 code.begin_block() 8751 code.put_ensure_gil(declare_gilstate=True) 8752 8753 code.put_giveref(Naming.parallel_exc_type) 8754 code.putln("__Pyx_ErrRestoreWithState(%s, %s, %s);" % self.parallel_exc) 8755 pos_info = chain(*zip(self.pos_info, self.parallel_pos_info)) 8756 code.putln("%s = %s; %s = %s; %s = %s;" % tuple(pos_info)) 8757 8758 code.put_release_ensured_gil() 8759 code.end_block() 8760 8761 def restore_labels(self, code): 8762 """ 8763 Restore all old labels. Call this before the 'else' clause to for 8764 loops and always before ending the parallel control flow block. 8765 """ 8766 code.set_all_labels(self.old_loop_labels + (self.old_return_label, 8767 self.old_error_label)) 8768 8769 def end_parallel_control_flow_block( 8770 self, code, break_=False, continue_=False, return_=False): 8771 """ 8772 This ends the parallel control flow block and based on how the parallel 8773 section was exited, takes the corresponding action. The break_ and 8774 continue_ parameters indicate whether these should be propagated 8775 outwards: 8776 8777 for i in prange(...): 8778 with cython.parallel.parallel(): 8779 continue 8780 8781 Here break should be trapped in the parallel block, and propagated to 8782 the for loop. 8783 """ 8784 c = self.begin_of_parallel_control_block_point 8785 self.begin_of_parallel_control_block_point = None 8786 self.begin_of_parallel_control_block_point_after_decls = None 8787 8788 if self.num_threads is not None: 8789 # FIXME: is it the right place? should not normally produce code. 8790 self.num_threads.generate_disposal_code(code) 8791 self.num_threads.free_temps(code) 8792 8793 # Firstly, always prefer errors over returning, continue or break 8794 if self.error_label_used: 8795 c.putln("const char *%s = NULL; int %s = 0, %s = 0;" % self.parallel_pos_info) 8796 c.putln("PyObject *%s = NULL, *%s = NULL, *%s = NULL;" % self.parallel_exc) 8797 8798 code.putln( 8799 "if (%s) {" % Naming.parallel_exc_type) 8800 code.putln("/* This may have been overridden by a continue, " 8801 "break or return in another thread. Prefer the error. */") 8802 code.putln("%s = 4;" % Naming.parallel_why) 8803 code.putln( 8804 "}") 8805 8806 if continue_: 8807 any_label_used = self.any_label_used 8808 else: 8809 any_label_used = self.breaking_label_used 8810 8811 if any_label_used: 8812 # __pyx_parallel_why is used, declare and initialize 8813 c.putln("int %s;" % Naming.parallel_why) 8814 c.putln("%s = 0;" % Naming.parallel_why) 8815 8816 code.putln( 8817 "if (%s) {" % Naming.parallel_why) 8818 8819 for temp_cname, private_cname in self.parallel_private_temps: 8820 code.putln("%s = %s;" % (private_cname, temp_cname)) 8821 8822 code.putln("switch (%s) {" % Naming.parallel_why) 8823 if continue_: 8824 code.put(" case 1: ") 8825 code.put_goto(code.continue_label) 8826 8827 if break_: 8828 code.put(" case 2: ") 8829 code.put_goto(code.break_label) 8830 8831 if return_: 8832 code.put(" case 3: ") 8833 code.put_goto(code.return_label) 8834 8835 if self.error_label_used: 8836 code.globalstate.use_utility_code(restore_exception_utility_code) 8837 code.putln(" case 4:") 8838 self.restore_parallel_exception(code) 8839 code.put_goto(code.error_label) 8840 8841 code.putln("}") # end switch 8842 code.putln( 8843 "}") # end if 8844 8845 code.end_block() # end parallel control flow block 8846 self.redef_builtin_expect_apple_gcc_bug(code) 8847 8848 # FIXME: improve with version number for OS X Lion 8849 buggy_platform_macro_condition = "(defined(__APPLE__) || defined(__OSX__))" 8850 have_expect_condition = "(defined(__GNUC__) && " \ 8851 "(__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))))" 8852 redef_condition = "(%s && %s)" % (buggy_platform_macro_condition, have_expect_condition) 8853 8854 def undef_builtin_expect_apple_gcc_bug(self, code): 8855 """ 8856 A bug on OS X Lion disallows __builtin_expect macros. This code avoids them 8857 """ 8858 if not self.parent: 8859 code.undef_builtin_expect(self.redef_condition) 8860 8861 def redef_builtin_expect_apple_gcc_bug(self, code): 8862 if not self.parent: 8863 code.redef_builtin_expect(self.redef_condition) 8864 8865 8866class ParallelWithBlockNode(ParallelStatNode): 8867 """ 8868 This node represents a 'with cython.parallel.parallel():' block 8869 """ 8870 8871 valid_keyword_arguments = ['num_threads'] 8872 8873 num_threads = None 8874 8875 def analyse_declarations(self, env): 8876 super(ParallelWithBlockNode, self).analyse_declarations(env) 8877 if self.args: 8878 error(self.pos, "cython.parallel.parallel() does not take " 8879 "positional arguments") 8880 8881 def generate_execution_code(self, code): 8882 self.declare_closure_privates(code) 8883 self.setup_parallel_control_flow_block(code) 8884 8885 code.putln("#ifdef _OPENMP") 8886 code.put("#pragma omp parallel ") 8887 8888 if self.privates: 8889 privates = [e.cname for e in self.privates 8890 if not e.type.is_pyobject] 8891 code.put('private(%s)' % ', '.join(sorted(privates))) 8892 8893 self.privatization_insertion_point = code.insertion_point() 8894 self.put_num_threads(code) 8895 code.putln("") 8896 8897 code.putln("#endif /* _OPENMP */") 8898 8899 code.begin_block() # parallel block 8900 self.begin_parallel_block(code) 8901 self.initialize_privates_to_nan(code) 8902 code.funcstate.start_collecting_temps() 8903 self.body.generate_execution_code(code) 8904 self.trap_parallel_exit(code) 8905 self.privatize_temps(code) 8906 self.end_parallel_block(code) 8907 code.end_block() # end parallel block 8908 8909 continue_ = code.label_used(code.continue_label) 8910 break_ = code.label_used(code.break_label) 8911 return_ = code.label_used(code.return_label) 8912 8913 self.restore_labels(code) 8914 self.end_parallel_control_flow_block(code, break_=break_, 8915 continue_=continue_, 8916 return_=return_) 8917 self.release_closure_privates(code) 8918 8919 8920class ParallelRangeNode(ParallelStatNode): 8921 """ 8922 This node represents a 'for i in cython.parallel.prange():' construct. 8923 8924 target NameNode the target iteration variable 8925 else_clause Node or None the else clause of this loop 8926 """ 8927 8928 child_attrs = ['body', 'target', 'else_clause', 'args', 'num_threads', 8929 'chunksize'] 8930 8931 body = target = else_clause = args = None 8932 8933 start = stop = step = None 8934 8935 is_prange = True 8936 8937 nogil = None 8938 schedule = None 8939 8940 valid_keyword_arguments = ['schedule', 'nogil', 'num_threads', 'chunksize'] 8941 8942 def __init__(self, pos, **kwds): 8943 super(ParallelRangeNode, self).__init__(pos, **kwds) 8944 # Pretend to be a ForInStatNode for control flow analysis 8945 self.iterator = PassStatNode(pos) 8946 8947 def analyse_declarations(self, env): 8948 super(ParallelRangeNode, self).analyse_declarations(env) 8949 self.target.analyse_target_declaration(env) 8950 if self.else_clause is not None: 8951 self.else_clause.analyse_declarations(env) 8952 8953 if not self.args or len(self.args) > 3: 8954 error(self.pos, "Invalid number of positional arguments to prange") 8955 return 8956 8957 if len(self.args) == 1: 8958 self.stop, = self.args 8959 elif len(self.args) == 2: 8960 self.start, self.stop = self.args 8961 else: 8962 self.start, self.stop, self.step = self.args 8963 8964 if hasattr(self.schedule, 'decode'): 8965 self.schedule = self.schedule.decode('ascii') 8966 8967 if self.schedule not in (None, 'static', 'dynamic', 'guided', 'runtime'): 8968 error(self.pos, "Invalid schedule argument to prange: %s" % (self.schedule,)) 8969 8970 def analyse_expressions(self, env): 8971 was_nogil = env.nogil 8972 if self.nogil: 8973 env.nogil = True 8974 8975 if self.target is None: 8976 error(self.pos, "prange() can only be used as part of a for loop") 8977 return self 8978 8979 self.target = self.target.analyse_target_types(env) 8980 8981 if not self.target.type.is_numeric: 8982 # Not a valid type, assume one for now anyway 8983 8984 if not self.target.type.is_pyobject: 8985 # nogil_check will catch the is_pyobject case 8986 error(self.target.pos, 8987 "Must be of numeric type, not %s" % self.target.type) 8988 8989 self.index_type = PyrexTypes.c_py_ssize_t_type 8990 else: 8991 self.index_type = self.target.type 8992 if not self.index_type.signed: 8993 warning(self.target.pos, 8994 "Unsigned index type not allowed before OpenMP 3.0", 8995 level=2) 8996 8997 # Setup start, stop and step, allocating temps if needed 8998 self.names = 'start', 'stop', 'step' 8999 start_stop_step = self.start, self.stop, self.step 9000 9001 for node, name in zip(start_stop_step, self.names): 9002 if node is not None: 9003 node.analyse_types(env) 9004 if not node.type.is_numeric: 9005 error(node.pos, "%s argument must be numeric" % name) 9006 continue 9007 9008 if not node.is_literal: 9009 node = node.coerce_to_temp(env) 9010 setattr(self, name, node) 9011 9012 # As we range from 0 to nsteps, computing the index along the 9013 # way, we need a fitting type for 'i' and 'nsteps' 9014 self.index_type = PyrexTypes.widest_numeric_type( 9015 self.index_type, node.type) 9016 9017 if self.else_clause is not None: 9018 self.else_clause = self.else_clause.analyse_expressions(env) 9019 9020 # Although not actually an assignment in this scope, it should be 9021 # treated as such to ensure it is unpacked if a closure temp, and to 9022 # ensure lastprivate behaviour and propagation. If the target index is 9023 # not a NameNode, it won't have an entry, and an error was issued by 9024 # ParallelRangeTransform 9025 if hasattr(self.target, 'entry'): 9026 self.assignments[self.target.entry] = self.target.pos, None 9027 9028 node = super(ParallelRangeNode, self).analyse_expressions(env) 9029 9030 if node.chunksize: 9031 if not node.schedule: 9032 error(node.chunksize.pos, 9033 "Must provide schedule with chunksize") 9034 elif node.schedule == 'runtime': 9035 error(node.chunksize.pos, 9036 "Chunksize not valid for the schedule runtime") 9037 elif (node.chunksize.type.is_int and 9038 node.chunksize.is_literal and 9039 node.chunksize.compile_time_value(env) <= 0): 9040 error(node.chunksize.pos, "Chunksize must not be negative") 9041 9042 node.chunksize = node.chunksize.coerce_to( 9043 PyrexTypes.c_int_type, env).coerce_to_temp(env) 9044 9045 if node.nogil: 9046 env.nogil = was_nogil 9047 9048 node.is_nested_prange = node.parent and node.parent.is_prange 9049 if node.is_nested_prange: 9050 parent = node 9051 while parent.parent and parent.parent.is_prange: 9052 parent = parent.parent 9053 9054 parent.assignments.update(node.assignments) 9055 parent.privates.update(node.privates) 9056 parent.assigned_nodes.extend(node.assigned_nodes) 9057 return node 9058 9059 def nogil_check(self, env): 9060 names = 'start', 'stop', 'step', 'target' 9061 nodes = self.start, self.stop, self.step, self.target 9062 for name, node in zip(names, nodes): 9063 if node is not None and node.type.is_pyobject: 9064 error(node.pos, "%s may not be a Python object " 9065 "as we don't have the GIL" % name) 9066 9067 def generate_execution_code(self, code): 9068 """ 9069 Generate code in the following steps 9070 9071 1) copy any closure variables determined thread-private 9072 into temporaries 9073 9074 2) allocate temps for start, stop and step 9075 9076 3) generate a loop that calculates the total number of steps, 9077 which then computes the target iteration variable for every step: 9078 9079 for i in prange(start, stop, step): 9080 ... 9081 9082 becomes 9083 9084 nsteps = (stop - start) / step; 9085 i = start; 9086 9087 #pragma omp parallel for lastprivate(i) 9088 for (temp = 0; temp < nsteps; temp++) { 9089 i = start + step * temp; 9090 ... 9091 } 9092 9093 Note that accumulation of 'i' would have a data dependency 9094 between iterations. 9095 9096 Also, you can't do this 9097 9098 for (i = start; i < stop; i += step) 9099 ... 9100 9101 as the '<' operator should become '>' for descending loops. 9102 'for i from x < i < y:' does not suffer from this problem 9103 as the relational operator is known at compile time! 9104 9105 4) release our temps and write back any private closure variables 9106 """ 9107 self.declare_closure_privates(code) 9108 9109 # This can only be a NameNode 9110 target_index_cname = self.target.entry.cname 9111 9112 # This will be used as the dict to format our code strings, holding 9113 # the start, stop , step, temps and target cnames 9114 fmt_dict = { 9115 'target': target_index_cname, 9116 'target_type': self.target.type.empty_declaration_code() 9117 } 9118 9119 # Setup start, stop and step, allocating temps if needed 9120 start_stop_step = self.start, self.stop, self.step 9121 defaults = '0', '0', '1' 9122 for node, name, default in zip(start_stop_step, self.names, defaults): 9123 if node is None: 9124 result = default 9125 elif node.is_literal: 9126 result = node.get_constant_c_result_code() 9127 else: 9128 node.generate_evaluation_code(code) 9129 result = node.result() 9130 9131 fmt_dict[name] = result 9132 9133 fmt_dict['i'] = code.funcstate.allocate_temp(self.index_type, False) 9134 fmt_dict['nsteps'] = code.funcstate.allocate_temp(self.index_type, False) 9135 9136 # TODO: check if the step is 0 and if so, raise an exception in a 9137 # 'with gil' block. For now, just abort 9138 code.putln("if ((%(step)s == 0)) abort();" % fmt_dict) 9139 9140 self.setup_parallel_control_flow_block(code) # parallel control flow block 9141 9142 # Note: nsteps is private in an outer scope if present 9143 code.putln("%(nsteps)s = (%(stop)s - %(start)s + %(step)s - %(step)s/abs(%(step)s)) / %(step)s;" % fmt_dict) 9144 9145 # The target iteration variable might not be initialized, do it only if 9146 # we are executing at least 1 iteration, otherwise we should leave the 9147 # target unaffected. The target iteration variable is firstprivate to 9148 # shut up compiler warnings caused by lastprivate, as the compiler 9149 # erroneously believes that nsteps may be <= 0, leaving the private 9150 # target index uninitialized 9151 code.putln("if (%(nsteps)s > 0)" % fmt_dict) 9152 code.begin_block() # if block 9153 self.generate_loop(code, fmt_dict) 9154 code.end_block() # end if block 9155 9156 self.restore_labels(code) 9157 9158 if self.else_clause: 9159 if self.breaking_label_used: 9160 code.put("if (%s < 2)" % Naming.parallel_why) 9161 9162 code.begin_block() # else block 9163 code.putln("/* else */") 9164 self.else_clause.generate_execution_code(code) 9165 code.end_block() # end else block 9166 9167 # ------ cleanup ------ 9168 self.end_parallel_control_flow_block(code) # end parallel control flow block 9169 9170 # And finally, release our privates and write back any closure 9171 # variables 9172 for temp in start_stop_step + (self.chunksize,): 9173 if temp is not None: 9174 temp.generate_disposal_code(code) 9175 temp.free_temps(code) 9176 9177 code.funcstate.release_temp(fmt_dict['i']) 9178 code.funcstate.release_temp(fmt_dict['nsteps']) 9179 9180 self.release_closure_privates(code) 9181 9182 def generate_loop(self, code, fmt_dict): 9183 if self.is_nested_prange: 9184 code.putln("#if 0") 9185 else: 9186 code.putln("#ifdef _OPENMP") 9187 9188 if not self.is_parallel: 9189 code.put("#pragma omp for") 9190 self.privatization_insertion_point = code.insertion_point() 9191 reduction_codepoint = self.parent.privatization_insertion_point 9192 else: 9193 code.put("#pragma omp parallel") 9194 self.privatization_insertion_point = code.insertion_point() 9195 reduction_codepoint = self.privatization_insertion_point 9196 code.putln("") 9197 code.putln("#endif /* _OPENMP */") 9198 9199 code.begin_block() # pragma omp parallel begin block 9200 9201 # Initialize the GIL if needed for this thread 9202 self.begin_parallel_block(code) 9203 9204 if self.is_nested_prange: 9205 code.putln("#if 0") 9206 else: 9207 code.putln("#ifdef _OPENMP") 9208 code.put("#pragma omp for") 9209 9210 for entry, (op, lastprivate) in sorted(self.privates.items()): 9211 # Don't declare the index variable as a reduction 9212 if op and op in "+*-&^|" and entry != self.target.entry: 9213 if entry.type.is_pyobject: 9214 error(self.pos, "Python objects cannot be reductions") 9215 else: 9216 #code.put(" reduction(%s:%s)" % (op, entry.cname)) 9217 # This is the only way reductions + nesting works in gcc4.5 9218 reduction_codepoint.put( 9219 " reduction(%s:%s)" % (op, entry.cname)) 9220 else: 9221 if entry == self.target.entry: 9222 code.put(" firstprivate(%s)" % entry.cname) 9223 code.put(" lastprivate(%s)" % entry.cname) 9224 continue 9225 9226 if not entry.type.is_pyobject: 9227 if lastprivate: 9228 private = 'lastprivate' 9229 else: 9230 private = 'private' 9231 9232 code.put(" %s(%s)" % (private, entry.cname)) 9233 9234 if self.schedule: 9235 if self.chunksize: 9236 chunksize = ", %s" % self.evaluate_before_block(code, self.chunksize) 9237 else: 9238 chunksize = "" 9239 9240 code.put(" schedule(%s%s)" % (self.schedule, chunksize)) 9241 9242 self.put_num_threads(reduction_codepoint) 9243 9244 code.putln("") 9245 code.putln("#endif /* _OPENMP */") 9246 9247 code.put("for (%(i)s = 0; %(i)s < %(nsteps)s; %(i)s++)" % fmt_dict) 9248 code.begin_block() # for loop block 9249 9250 guard_around_body_codepoint = code.insertion_point() 9251 9252 # Start if guard block around the body. This may be unnecessary, but 9253 # at least it doesn't spoil indentation 9254 code.begin_block() 9255 9256 code.putln("%(target)s = (%(target_type)s)(%(start)s + %(step)s * %(i)s);" % fmt_dict) 9257 self.initialize_privates_to_nan(code, exclude=self.target.entry) 9258 9259 if self.is_parallel and not self.is_nested_prange: 9260 # nested pranges are not omp'ified, temps go to outer loops 9261 code.funcstate.start_collecting_temps() 9262 9263 self.body.generate_execution_code(code) 9264 self.trap_parallel_exit(code, should_flush=True) 9265 if self.is_parallel and not self.is_nested_prange: 9266 # nested pranges are not omp'ified, temps go to outer loops 9267 self.privatize_temps(code) 9268 9269 if self.breaking_label_used: 9270 # Put a guard around the loop body in case return, break or 9271 # exceptions might be used 9272 guard_around_body_codepoint.putln("if (%s < 2)" % Naming.parallel_why) 9273 9274 code.end_block() # end guard around loop body 9275 code.end_block() # end for loop block 9276 9277 if self.is_parallel: 9278 # Release the GIL and deallocate the thread state 9279 self.end_parallel_block(code) 9280 code.end_block() # pragma omp parallel end block 9281 9282 9283class CnameDecoratorNode(StatNode): 9284 """ 9285 This node is for the cname decorator in CythonUtilityCode: 9286 9287 @cname('the_cname') 9288 cdef func(...): 9289 ... 9290 9291 In case of a cdef class the cname specifies the objstruct_cname. 9292 9293 node the node to which the cname decorator is applied 9294 cname the cname the node should get 9295 """ 9296 9297 child_attrs = ['node'] 9298 9299 def analyse_declarations(self, env): 9300 self.node.analyse_declarations(env) 9301 9302 node = self.node 9303 if isinstance(node, CompilerDirectivesNode): 9304 node = node.body.stats[0] 9305 9306 self.is_function = isinstance(node, FuncDefNode) 9307 is_struct_or_enum = isinstance(node, (CStructOrUnionDefNode, CEnumDefNode)) 9308 e = node.entry 9309 9310 if self.is_function: 9311 e.cname = self.cname 9312 e.func_cname = self.cname 9313 e.used = True 9314 if e.pyfunc_cname and '.' in e.pyfunc_cname: 9315 e.pyfunc_cname = self.mangle(e.pyfunc_cname) 9316 elif is_struct_or_enum: 9317 e.cname = e.type.cname = self.cname 9318 else: 9319 scope = node.scope 9320 9321 e.cname = self.cname 9322 e.type.objstruct_cname = self.cname + '_obj' 9323 e.type.typeobj_cname = Naming.typeobj_prefix + self.cname 9324 e.type.typeptr_cname = self.cname + '_type' 9325 e.type.scope.namespace_cname = e.type.typeptr_cname 9326 9327 e.as_variable.cname = e.type.typeptr_cname 9328 9329 scope.scope_prefix = self.cname + "_" 9330 9331 for name, entry in scope.entries.items(): 9332 if entry.func_cname: 9333 entry.func_cname = self.mangle(entry.cname) 9334 if entry.pyfunc_cname: 9335 entry.pyfunc_cname = self.mangle(entry.pyfunc_cname) 9336 9337 def mangle(self, cname): 9338 if '.' in cname: 9339 # remove __pyx_base from func_cname 9340 cname = cname.split('.')[-1] 9341 return '%s_%s' % (self.cname, cname) 9342 9343 def analyse_expressions(self, env): 9344 self.node = self.node.analyse_expressions(env) 9345 return self 9346 9347 def generate_function_definitions(self, env, code): 9348 "Ensure a prototype for every @cname method in the right place" 9349 if self.is_function and env.is_c_class_scope: 9350 # method in cdef class, generate a prototype in the header 9351 h_code = code.globalstate['utility_code_proto'] 9352 9353 if isinstance(self.node, DefNode): 9354 self.node.generate_function_header( 9355 h_code, with_pymethdef=False, proto_only=True) 9356 else: 9357 from . import ModuleNode 9358 entry = self.node.entry 9359 cname = entry.cname 9360 entry.cname = entry.func_cname 9361 9362 ModuleNode.generate_cfunction_declaration( 9363 entry, 9364 env.global_scope(), 9365 h_code, 9366 definition=True) 9367 9368 entry.cname = cname 9369 9370 self.node.generate_function_definitions(env, code) 9371 9372 def generate_execution_code(self, code): 9373 self.node.generate_execution_code(code) 9374 9375 9376#------------------------------------------------------------------------------------ 9377# 9378# Runtime support code 9379# 9380#------------------------------------------------------------------------------------ 9381 9382if Options.gcc_branch_hints: 9383 branch_prediction_macros = """ 9384/* Test for GCC > 2.95 */ 9385#if defined(__GNUC__) \ 9386 && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) 9387 #define likely(x) __builtin_expect(!!(x), 1) 9388 #define unlikely(x) __builtin_expect(!!(x), 0) 9389#else /* !__GNUC__ or GCC < 2.95 */ 9390 #define likely(x) (x) 9391 #define unlikely(x) (x) 9392#endif /* __GNUC__ */ 9393""" 9394else: 9395 branch_prediction_macros = """ 9396#define likely(x) (x) 9397#define unlikely(x) (x) 9398""" 9399 9400#------------------------------------------------------------------------------------ 9401 9402printing_utility_code = UtilityCode.load_cached("Print", "Printing.c") 9403printing_one_utility_code = UtilityCode.load_cached("PrintOne", "Printing.c") 9404 9405#------------------------------------------------------------------------------------ 9406 9407# Exception raising code 9408# 9409# Exceptions are raised by __Pyx_Raise() and stored as plain 9410# type/value/tb in PyThreadState->curexc_*. When being caught by an 9411# 'except' statement, curexc_* is moved over to exc_* by 9412# __Pyx_GetException() 9413 9414restore_exception_utility_code = UtilityCode.load_cached("PyErrFetchRestore", "Exceptions.c") 9415raise_utility_code = UtilityCode.load_cached("RaiseException", "Exceptions.c") 9416get_exception_utility_code = UtilityCode.load_cached("GetException", "Exceptions.c") 9417swap_exception_utility_code = UtilityCode.load_cached("SwapException", "Exceptions.c") 9418reset_exception_utility_code = UtilityCode.load_cached("SaveResetException", "Exceptions.c") 9419traceback_utility_code = UtilityCode.load_cached("AddTraceback", "Exceptions.c") 9420 9421#------------------------------------------------------------------------------------ 9422 9423get_exception_tuple_utility_code = UtilityCode( 9424 proto=""" 9425static PyObject *__Pyx_GetExceptionTuple(PyThreadState *__pyx_tstate); /*proto*/ 9426""", 9427 # I doubt that calling __Pyx_GetException() here is correct as it moves 9428 # the exception from tstate->curexc_* to tstate->exc_*, which prevents 9429 # exception handlers later on from receiving it. 9430 # NOTE: "__pyx_tstate" may be used by __Pyx_GetException() macro 9431 impl = """ 9432static PyObject *__Pyx_GetExceptionTuple(CYTHON_UNUSED PyThreadState *__pyx_tstate) { 9433 PyObject *type = NULL, *value = NULL, *tb = NULL; 9434 if (__Pyx_GetException(&type, &value, &tb) == 0) { 9435 PyObject* exc_info = PyTuple_New(3); 9436 if (exc_info) { 9437 Py_INCREF(type); 9438 Py_INCREF(value); 9439 Py_INCREF(tb); 9440 PyTuple_SET_ITEM(exc_info, 0, type); 9441 PyTuple_SET_ITEM(exc_info, 1, value); 9442 PyTuple_SET_ITEM(exc_info, 2, tb); 9443 return exc_info; 9444 } 9445 } 9446 return NULL; 9447} 9448""", 9449 requires=[get_exception_utility_code]) 9450