3 from Cython
.Compiler
import (ExprNodes
, PyrexTypes
, MemoryView
,
4 ParseTreeTransforms
, StringEncoding
,
6 from Cython
.Compiler
.ExprNodes
import CloneNode
, ProxyNode
, TupleNode
7 from Cython
.Compiler
.Nodes
import (FuncDefNode
, CFuncDefNode
, StatListNode
,
10 class FusedCFuncDefNode(StatListNode
):
12 This node replaces a function with fused arguments. It deep-copies the
13 function for every permutation of fused types, and allocates a new local
14 scope for it. It keeps track of the original function in self.node, and
15 the entry of the original function in the symbol table is given the
16 'fused_cfunction' attribute which points back to us.
17 Then when a function lookup occurs (to e.g. call it), the call can be
18 dispatched to the right function.
20 node FuncDefNode the original function
21 nodes [FuncDefNode] list of copies of node with different specific types
22 py_func DefNode the fused python function subscriptable from
24 __signatures__ A DictNode mapping signature specialization strings
26 resulting_fused_function PyCFunction for the fused DefNode that delegates
28 fused_func_assignment Assignment of the fused function to the function name
29 defaults_tuple TupleNode of defaults (letting PyCFunctionNode build
30 defaults would result in many different tuples)
31 specialized_pycfuncs List of synthesized pycfunction nodes for the
33 code_object CodeObjectNode shared by all specializations and the
36 fused_compound_types All fused (compound) types (e.g. floating[:])
40 resulting_fused_function
= None
41 fused_func_assignment
= None
45 child_attrs
= StatListNode
.child_attrs
+ [
46 '__signatures__', 'resulting_fused_function', 'fused_func_assignment']
48 def __init__(self
, node
, env
):
49 super(FusedCFuncDefNode
, self
).__init
__(node
.pos
)
54 is_def
= isinstance(self
.node
, DefNode
)
56 # self.node.decorators = []
61 # Perform some sanity checks. If anything fails, it's a bug
63 assert not n
.entry
.type.is_fused
64 assert not n
.local_scope
.return_type
.is_fused
65 if node
.return_type
.is_fused
:
66 assert not n
.return_type
.is_fused
68 if not is_def
and n
.cfunc_declarator
.optional_arg_count
:
69 assert n
.type.op_arg_struct
71 node
.entry
.fused_cfunction
= self
72 # Copy the nodes as AnalyseDeclarationsTransform will prepend
73 # self.py_func to self.stats, as we only want specialized
74 # CFuncDefNodes in self.nodes
75 self
.stats
= self
.nodes
[:]
77 def copy_def(self
, env
):
79 Create a copy of the original def or lambda function for specialized
82 fused_compound_types
= PyrexTypes
.unique(
83 [arg
.type for arg
in self
.node
.args
if arg
.type.is_fused
])
84 permutations
= PyrexTypes
.get_all_specialized_permutations(fused_compound_types
)
86 self
.fused_compound_types
= fused_compound_types
88 if self
.node
.entry
in env
.pyfunc_entries
:
89 env
.pyfunc_entries
.remove(self
.node
.entry
)
91 for cname
, fused_to_specific
in permutations
:
92 copied_node
= copy
.deepcopy(self
.node
)
94 self
._specialize
_function
_args
(copied_node
.args
, fused_to_specific
)
95 copied_node
.return_type
= self
.node
.return_type
.specialize(
98 copied_node
.analyse_declarations(env
)
99 # copied_node.is_staticmethod = self.node.is_staticmethod
100 # copied_node.is_classmethod = self.node.is_classmethod
101 self
.create_new_local_scope(copied_node
, env
, fused_to_specific
)
102 self
.specialize_copied_def(copied_node
, cname
, self
.node
.entry
,
103 fused_to_specific
, fused_compound_types
)
105 PyrexTypes
.specialize_entry(copied_node
.entry
, cname
)
106 copied_node
.entry
.used
= True
107 env
.entries
[copied_node
.entry
.name
] = copied_node
.entry
109 if not self
.replace_fused_typechecks(copied_node
):
112 self
.orig_py_func
= self
.node
113 self
.py_func
= self
.make_fused_cpdef(self
.node
, env
, is_def
=True)
115 def copy_cdef(self
, env
):
117 Create a copy of the original c(p)def function for all specialized
120 permutations
= self
.node
.type.get_all_specialized_permutations()
121 # print 'Node %s has %d specializations:' % (self.node.entry.name,
123 # import pprint; pprint.pprint([d for cname, d in permutations])
125 if self
.node
.entry
in env
.cfunc_entries
:
126 env
.cfunc_entries
.remove(self
.node
.entry
)
128 # Prevent copying of the python function
129 self
.orig_py_func
= orig_py_func
= self
.node
.py_func
130 self
.node
.py_func
= None
132 env
.pyfunc_entries
.remove(orig_py_func
.entry
)
134 fused_types
= self
.node
.type.get_fused_types()
135 self
.fused_compound_types
= fused_types
137 for cname
, fused_to_specific
in permutations
:
138 copied_node
= copy
.deepcopy(self
.node
)
140 # Make the types in our CFuncType specific
141 type = copied_node
.type.specialize(fused_to_specific
)
142 entry
= copied_node
.entry
144 copied_node
.type = type
145 entry
.type, type.entry
= type, entry
147 entry
.used
= (entry
.used
or
148 self
.node
.entry
.defined_in_pxd
or
149 env
.is_c_class_scope
or
152 if self
.node
.cfunc_declarator
.optional_arg_count
:
153 self
.node
.cfunc_declarator
.declare_optional_arg_struct(
154 type, env
, fused_cname
=cname
)
156 copied_node
.return_type
= type.return_type
157 self
.create_new_local_scope(copied_node
, env
, fused_to_specific
)
159 # Make the argument types in the CFuncDeclarator specific
160 self
._specialize
_function
_args
(copied_node
.cfunc_declarator
.args
,
163 type.specialize_entry(entry
, cname
)
164 env
.cfunc_entries
.append(entry
)
166 # If a cpdef, declare all specialized cpdefs (this
167 # also calls analyse_declarations)
168 copied_node
.declare_cpdef_wrapper(env
)
169 if copied_node
.py_func
:
170 env
.pyfunc_entries
.remove(copied_node
.py_func
.entry
)
172 self
.specialize_copied_def(
173 copied_node
.py_func
, cname
, self
.node
.entry
.as_variable
,
174 fused_to_specific
, fused_types
)
176 if not self
.replace_fused_typechecks(copied_node
):
180 self
.py_func
= self
.make_fused_cpdef(orig_py_func
, env
,
183 self
.py_func
= orig_py_func
185 def _specialize_function_args(self
, args
, fused_to_specific
):
187 if arg
.type.is_fused
:
188 arg
.type = arg
.type.specialize(fused_to_specific
)
189 if arg
.type.is_memoryviewslice
:
190 MemoryView
.validate_memslice_dtype(arg
.pos
, arg
.type.dtype
)
192 def create_new_local_scope(self
, node
, env
, f2s
):
194 Create a new local scope for the copied node and append it to
195 self.nodes. A new local scope is needed because the arguments with the
196 fused types are aready in the local scope, and we need the specialized
197 entries created after analyse_declarations on each specialized version
198 of the (CFunc)DefNode.
199 f2s is a dict mapping each fused type to its specialized version
201 node
.create_local_scope(env
)
202 node
.local_scope
.fused_to_specific
= f2s
204 # This is copied from the original function, set it to false to
206 node
.has_fused_arguments
= False
207 self
.nodes
.append(node
)
209 def specialize_copied_def(self
, node
, cname
, py_entry
, f2s
, fused_types
):
210 """Specialize the copy of a DefNode given the copied node,
211 the specialization cname and the original DefNode entry"""
213 PyrexTypes
.specialization_signature_string(fused_type
, f2s
)
214 for fused_type
in fused_types
217 node
.specialized_signature_string
= '|'.join(type_strings
)
219 node
.entry
.pymethdef_cname
= PyrexTypes
.get_fused_cname(
220 cname
, node
.entry
.pymethdef_cname
)
221 node
.entry
.doc
= py_entry
.doc
222 node
.entry
.doc_cname
= py_entry
.doc_cname
224 def replace_fused_typechecks(self
, copied_node
):
226 Branch-prune fused type checks like
231 Returns whether an error was issued and whether we should stop in
232 in order to prevent a flood of errors.
234 num_errors
= Errors
.num_errors
235 transform
= ParseTreeTransforms
.ReplaceFusedTypeChecks(
236 copied_node
.local_scope
)
237 transform(copied_node
)
239 if Errors
.num_errors
> num_errors
:
244 def _fused_instance_checks(self
, normal_types
, pyx_code
, env
):
246 Genereate Cython code for instance checks, matching an object to
250 for specialized_type
in normal_types
:
251 # all_numeric = all_numeric and specialized_type.is_numeric
252 py_type_name
= specialized_type
.py_type_name()
253 specialized_type_name
= specialized_type
.specialization_string
254 pyx_code
.context
.update(locals())
257 {{if_}} isinstance(arg, {{py_type_name}}):
258 dest_sig[{{dest_sig_idx}}] = '{{specialized_type_name}}'
263 # we need an 'if' to match the following 'else'
264 pyx_code
.putln("if 0: pass")
266 def _dtype_name(self
, dtype
):
268 return '___pyx_%s' % dtype
269 return str(dtype
).replace(' ', '_')
271 def _dtype_type(self
, dtype
):
273 return self
._dtype
_name
(dtype
)
276 def _sizeof_dtype(self
, dtype
):
277 if dtype
.is_pyobject
:
278 return 'sizeof(void *)'
280 return "sizeof(%s)" % self
._dtype
_type
(dtype
)
282 def _buffer_check_numpy_dtype_setup_cases(self
, pyx_code
):
283 "Setup some common cases to match dtypes against specializations"
284 if pyx_code
.indenter("if dtype.kind in ('i', 'u'):"):
285 pyx_code
.putln("pass")
286 pyx_code
.named_insertion_point("dtype_int")
289 if pyx_code
.indenter("elif dtype.kind == 'f':"):
290 pyx_code
.putln("pass")
291 pyx_code
.named_insertion_point("dtype_float")
294 if pyx_code
.indenter("elif dtype.kind == 'c':"):
295 pyx_code
.putln("pass")
296 pyx_code
.named_insertion_point("dtype_complex")
299 if pyx_code
.indenter("elif dtype.kind == 'O':"):
300 pyx_code
.putln("pass")
301 pyx_code
.named_insertion_point("dtype_object")
304 match
= "dest_sig[{{dest_sig_idx}}] = '{{specialized_type_name}}'"
305 no_match
= "dest_sig[{{dest_sig_idx}}] = None"
306 def _buffer_check_numpy_dtype(self
, pyx_code
, specialized_buffer_types
):
308 Match a numpy dtype object to the individual specializations.
310 self
._buffer
_check
_numpy
_dtype
_setup
_cases
(pyx_code
)
312 for specialized_type
in specialized_buffer_types
:
313 dtype
= specialized_type
.dtype
314 pyx_code
.context
.update(
315 itemsize_match
=self
._sizeof
_dtype
(dtype
) + " == itemsize",
316 signed_match
="not (%s_is_signed ^ dtype_signed)" % self
._dtype
_name
(dtype
),
318 specialized_type_name
=specialized_type
.specialization_string
)
321 (dtype
.is_int
, pyx_code
.dtype_int
),
322 (dtype
.is_float
, pyx_code
.dtype_float
),
323 (dtype
.is_complex
, pyx_code
.dtype_complex
)
326 for dtype_category
, codewriter
in dtypes
:
328 cond
= '{{itemsize_match}} and arg.ndim == %d' % (
329 specialized_type
.ndim
,)
331 cond
+= ' and {{signed_match}}'
333 if codewriter
.indenter("if %s:" % cond
):
334 # codewriter.putln("print 'buffer match found based on numpy dtype'")
335 codewriter
.putln(self
.match
)
336 codewriter
.putln("break")
339 def _buffer_parse_format_string_check(self
, pyx_code
, decl_code
,
340 specialized_type
, env
):
342 For each specialized type, try to coerce the object to a memoryview
343 slice of that type. This means obtaining a buffer and parsing the
345 TODO: separate buffer acquisition from format parsing
347 dtype
= specialized_type
.dtype
348 if specialized_type
.is_buffer
:
349 axes
= [('direct', 'strided')] * specialized_type
.ndim
351 axes
= specialized_type
.axes
353 memslice_type
= PyrexTypes
.MemoryViewSliceType(dtype
, axes
)
354 memslice_type
.create_from_py_utility_code(env
)
355 pyx_code
.context
.update(
356 coerce_from_py_func
=memslice_type
.from_py_function
,
359 "{{memviewslice_cname}} {{coerce_from_py_func}}(object)")
361 pyx_code
.context
.update(
362 specialized_type_name
=specialized_type
.specialization_string
,
363 sizeof_dtype
=self
._sizeof
_dtype
(dtype
))
368 if itemsize == -1 or itemsize == {{sizeof_dtype}}:
369 memslice = {{coerce_from_py_func}}(arg)
371 __PYX_XDEC_MEMVIEW(&memslice, 1)
372 # print 'found a match for the buffer through format parsing'
379 def _buffer_checks(self
, buffer_types
, pyx_code
, decl_code
, env
):
381 Generate Cython code to match objects to buffer specializations.
382 First try to get a numpy dtype object and match it against the individual
383 specializations. If that fails, try naively to coerce the object
384 to each specialization, which obtains the buffer each time and tries
385 to match the format string.
387 from Cython
.Compiler
import ExprNodes
389 if pyx_code
.indenter(u
"else:"):
390 # The first thing to find a match in this loop breaks out of the loop
391 if pyx_code
.indenter(u
"while 1:"):
394 if numpy is not None:
395 if isinstance(arg, numpy.ndarray):
397 elif (__pyx_memoryview_check(arg) and
398 isinstance(arg.base, numpy.ndarray)):
399 dtype = arg.base.dtype
404 if dtype is not None:
405 itemsize = dtype.itemsize
406 kind = ord(dtype.kind)
407 dtype_signed = kind == ord('i')
410 pyx_code
.named_insertion_point("numpy_dtype_checks")
411 self
._buffer
_check
_numpy
_dtype
(pyx_code
, buffer_types
)
414 for specialized_type
in buffer_types
:
415 self
._buffer
_parse
_format
_string
_check
(
416 pyx_code
, decl_code
, specialized_type
, env
)
418 pyx_code
.putln(self
.no_match
)
419 pyx_code
.putln("break")
424 pyx_code
.putln("else: %s" % self
.no_match
)
426 def _buffer_declarations(self
, pyx_code
, decl_code
, all_buffer_types
):
428 If we have any buffer specializations, write out some variable
429 declarations and imports.
433 ctypedef struct {{memviewslice_cname}}:
436 void __PYX_XDEC_MEMVIEW({{memviewslice_cname}} *, int have_gil)
437 bint __pyx_memoryview_check(object)
440 pyx_code
.local_variable_declarations
.put_chunk(
442 cdef {{memviewslice_cname}} memslice
443 cdef Py_ssize_t itemsize
444 cdef bint dtype_signed
450 pyx_code
.imports
.put_chunk(
458 seen_int_dtypes
= set()
459 for buffer_type
in all_buffer_types
:
460 dtype
= buffer_type
.dtype
462 #decl_code.putln("ctypedef %s %s" % (dtype.resolve(),
463 # self._dtype_name(dtype)))
464 decl_code
.putln('ctypedef %s %s "%s"' % (dtype
.resolve(),
465 self
._dtype
_name
(dtype
),
466 dtype
.declaration_code("")))
468 if buffer_type
.dtype
.is_int
:
469 if str(dtype
) not in seen_int_dtypes
:
470 seen_int_dtypes
.add(str(dtype
))
471 pyx_code
.context
.update(dtype_name
=self
._dtype
_name
(dtype
),
472 dtype_type
=self
._dtype
_type
(dtype
))
473 pyx_code
.local_variable_declarations
.put_chunk(
475 cdef bint {{dtype_name}}_is_signed
476 {{dtype_name}}_is_signed = <{{dtype_type}}> -1 < 0
479 def _split_fused_types(self
, arg
):
481 Specialize fused types and split into normal types and buffer types.
483 specialized_types
= PyrexTypes
.get_specialized_types(arg
.type)
484 # Prefer long over int, etc
485 # specialized_types.sort()
486 seen_py_type_names
= set()
487 normal_types
, buffer_types
= [], []
488 for specialized_type
in specialized_types
:
489 py_type_name
= specialized_type
.py_type_name()
491 if py_type_name
in seen_py_type_names
:
493 seen_py_type_names
.add(py_type_name
)
494 normal_types
.append(specialized_type
)
495 elif specialized_type
.is_buffer
or specialized_type
.is_memoryviewslice
:
496 buffer_types
.append(specialized_type
)
498 return normal_types
, buffer_types
500 def _unpack_argument(self
, pyx_code
):
503 # PROCESSING ARGUMENT {{arg_tuple_idx}}
504 if {{arg_tuple_idx}} < len(args):
505 arg = args[{{arg_tuple_idx}}]
506 elif '{{arg.name}}' in kwargs:
507 arg = kwargs['{{arg.name}}']
510 arg = defaults[{{default_idx}}]
512 raise TypeError("Expected at least %d arguments" % len(args))
516 def make_fused_cpdef(self
, orig_py_func
, env
, is_def
):
518 This creates the function that is indexable from Python and does
519 runtime dispatch based on the argument types. The function gets the
520 arg tuple and kwargs dict (or None) and the defaults tuple
521 as arguments from the Binding Fused Function's tp_call.
523 from Cython
.Compiler
import TreeFragment
, Code
, MemoryView
, UtilityCode
525 # { (arg_pos, FusedType) : specialized_type }
526 seen_fused_types
= set()
529 'memviewslice_cname': MemoryView
.memviewslice_cname
,
530 'func_args': self
.node
.args
,
531 'n_fused': len([arg
for arg
in self
.node
.args
]),
532 'name': orig_py_func
.entry
.name
,
535 pyx_code
= Code
.PyxCodeWriter(context
=context
)
536 decl_code
= Code
.PyxCodeWriter(context
=context
)
540 void __pyx_PyErr_Clear "PyErr_Clear" ()
546 def __pyx_fused_cpdef(signatures, args, kwargs, defaults):
547 dest_sig = [{{for _ in range(n_fused)}}None,{{endfor}}]
554 # instance check body
556 pyx_code
.indent() # indent following code to function body
557 pyx_code
.named_insertion_point("imports")
558 pyx_code
.named_insertion_point("local_variable_declarations")
562 all_buffer_types
= set()
563 for i
, arg
in enumerate(self
.node
.args
):
564 if arg
.type.is_fused
and arg
.type not in seen_fused_types
:
565 seen_fused_types
.add(arg
.type)
570 dest_sig_idx
=fused_index
,
571 default_idx
=default_idx
,
574 normal_types
, buffer_types
= self
._split
_fused
_types
(arg
)
575 self
._unpack
_argument
(pyx_code
)
576 self
._fused
_instance
_checks
(normal_types
, pyx_code
, env
)
577 self
._buffer
_checks
(buffer_types
, pyx_code
, decl_code
, env
)
580 all_buffer_types
.update(buffer_types
)
586 self
._buffer
_declarations
(pyx_code
, decl_code
, all_buffer_types
)
587 env
.use_utility_code(Code
.UtilityCode
.load_cached("Import", "ImportExport.c"))
592 for sig in signatures:
594 for src_type, dst_type in zip(sig.strip('()').split('|'), dest_sig):
595 if dst_type is not None:
596 if src_type == dst_type:
603 candidates.append(sig)
606 raise TypeError("No matching signature found")
607 elif len(candidates) > 1:
608 raise TypeError("Function call with ambiguous argument types")
610 return signatures[candidates[0]]
613 fragment_code
= pyx_code
.getvalue()
614 # print decl_code.getvalue()
615 # print fragment_code
616 fragment
= TreeFragment
.TreeFragment(fragment_code
, level
='module')
617 ast
= TreeFragment
.SetPosTransform(self
.node
.pos
)(fragment
.root
)
618 UtilityCode
.declare_declarations_in_scope(decl_code
.getvalue(),
621 ast
.analyse_declarations(env
)
622 py_func
= ast
.stats
[-1] # the DefNode
623 self
.fragment_scope
= ast
.scope
625 if isinstance(self
.node
, DefNode
):
626 py_func
.specialized_cpdefs
= self
.nodes
[:]
628 py_func
.specialized_cpdefs
= [n
.py_func
for n
in self
.nodes
]
632 def update_fused_defnode_entry(self
, env
):
634 'name', 'pos', 'cname', 'func_cname', 'pyfunc_cname',
635 'pymethdef_cname', 'doc', 'doc_cname', 'is_member',
639 entry
= self
.py_func
.entry
641 for attr
in copy_attributes
:
643 getattr(self
.orig_py_func
.entry
, attr
))
645 self
.py_func
.name
= self
.orig_py_func
.name
646 self
.py_func
.doc
= self
.orig_py_func
.doc
648 env
.entries
.pop('__pyx_fused_cpdef', None)
649 if isinstance(self
.node
, DefNode
):
650 env
.entries
[entry
.name
] = entry
652 env
.entries
[entry
.name
].as_variable
= entry
654 env
.pyfunc_entries
.append(entry
)
656 self
.py_func
.entry
.fused_cfunction
= self
657 for node
in self
.nodes
:
658 if isinstance(self
.node
, DefNode
):
659 node
.fused_py_func
= self
.py_func
661 node
.py_func
.fused_py_func
= self
.py_func
662 node
.entry
.as_variable
= entry
664 self
.synthesize_defnodes()
665 self
.stats
.append(self
.__signatures
__)
667 def analyse_expressions(self
, env
):
669 Analyse the expressions. Take care to only evaluate default arguments
670 once and clone the result for all specializations
672 for fused_compound_type
in self
.fused_compound_types
:
673 for fused_type
in fused_compound_type
.get_fused_types():
674 for specialization_type
in fused_type
.types
:
675 if specialization_type
.is_complex
:
676 specialization_type
.create_declaration_utility_code(env
)
679 self
.__signatures
__ = self
.__signatures
__.analyse_expressions(env
)
680 self
.py_func
= self
.py_func
.analyse_expressions(env
)
681 self
.resulting_fused_function
= self
.resulting_fused_function
.analyse_expressions(env
)
682 self
.fused_func_assignment
= self
.fused_func_assignment
.analyse_expressions(env
)
684 self
.defaults
= defaults
= []
686 for arg
in self
.node
.args
:
688 arg
.default
= arg
.default
.analyse_expressions(env
)
689 defaults
.append(ProxyNode(arg
.default
))
691 defaults
.append(None)
693 for i
, stat
in enumerate(self
.stats
):
694 stat
= self
.stats
[i
] = stat
.analyse_expressions(env
)
695 if isinstance(stat
, FuncDefNode
):
696 for arg
, default
in zip(stat
.args
, defaults
):
697 if default
is not None:
698 arg
.default
= CloneNode(default
).coerce_to(arg
.type, env
)
701 args
= [CloneNode(default
) for default
in defaults
if default
]
702 self
.defaults_tuple
= TupleNode(self
.pos
, args
=args
)
703 self
.defaults_tuple
= self
.defaults_tuple
.analyse_types(env
, skip_children
=True)
704 self
.defaults_tuple
= ProxyNode(self
.defaults_tuple
)
705 self
.code_object
= ProxyNode(self
.specialized_pycfuncs
[0].code_object
)
707 fused_func
= self
.resulting_fused_function
.arg
708 fused_func
.defaults_tuple
= CloneNode(self
.defaults_tuple
)
709 fused_func
.code_object
= CloneNode(self
.code_object
)
711 for i
, pycfunc
in enumerate(self
.specialized_pycfuncs
):
712 pycfunc
.code_object
= CloneNode(self
.code_object
)
713 pycfunc
= self
.specialized_pycfuncs
[i
] = pycfunc
.analyse_types(env
)
714 pycfunc
.defaults_tuple
= CloneNode(self
.defaults_tuple
)
717 def synthesize_defnodes(self
):
719 Create the __signatures__ dict of PyCFunctionNode specializations.
721 if isinstance(self
.nodes
[0], CFuncDefNode
):
722 nodes
= [node
.py_func
for node
in self
.nodes
]
727 StringEncoding
.EncodedString(node
.specialized_signature_string
)
729 keys
= [ExprNodes
.StringNode(node
.pos
, value
=sig
)
730 for node
, sig
in zip(nodes
, signatures
)]
731 values
= [ExprNodes
.PyCFunctionNode
.from_defnode(node
, True)
733 self
.__signatures
__ = ExprNodes
.DictNode
.from_pairs(self
.pos
,
736 self
.specialized_pycfuncs
= values
737 for pycfuncnode
in values
:
738 pycfuncnode
.is_specialization
= True
740 def generate_function_definitions(self
, env
, code
):
742 self
.py_func
.pymethdef_required
= True
743 self
.fused_func_assignment
.generate_function_definitions(env
, code
)
745 for stat
in self
.stats
:
746 if isinstance(stat
, FuncDefNode
) and stat
.entry
.used
:
747 code
.mark_pos(stat
.pos
)
748 stat
.generate_function_definitions(env
, code
)
750 def generate_execution_code(self
, code
):
751 # Note: all def function specialization are wrapped in PyCFunction
752 # nodes in the self.__signatures__ dictnode.
753 for default
in self
.defaults
:
754 if default
is not None:
755 default
.generate_evaluation_code(code
)
758 self
.defaults_tuple
.generate_evaluation_code(code
)
759 self
.code_object
.generate_evaluation_code(code
)
761 for stat
in self
.stats
:
762 code
.mark_pos(stat
.pos
)
763 if isinstance(stat
, ExprNodes
.ExprNode
):
764 stat
.generate_evaluation_code(code
)
766 stat
.generate_execution_code(code
)
768 if self
.__signatures
__:
769 self
.resulting_fused_function
.generate_evaluation_code(code
)
772 "((__pyx_FusedFunctionObject *) %s)->__signatures__ = %s;" %
773 (self
.resulting_fused_function
.result(),
774 self
.__signatures
__.result()))
775 code
.put_giveref(self
.__signatures
__.result())
777 self
.fused_func_assignment
.generate_execution_code(code
)
780 self
.resulting_fused_function
.generate_disposal_code(code
)
781 self
.defaults_tuple
.generate_disposal_code(code
)
782 self
.code_object
.generate_disposal_code(code
)
784 for default
in self
.defaults
:
785 if default
is not None:
786 default
.generate_disposal_code(code
)
788 def annotate(self
, code
):
789 for stat
in self
.stats
: