B
    Í‹d¢“  ã               @   s€   d dl mZ d dlZddlmZmZmZmZmZm	Z	 ddlm
Z
mZmZ ddlmZmZmZmZ ddlmZ G d	d
„ d
eƒZdS )é    )Úabsolute_importNé   )Ú	ExprNodesÚ
PyrexTypesÚ
MemoryViewÚParseTreeTransformsÚStringEncodingÚErrors)Ú	CloneNodeÚ	ProxyNodeÚ	TupleNode)ÚFuncDefNodeÚCFuncDefNodeÚStatListNodeÚDefNodeé   )Ú
OrderedSetc                   s  e Zd ZdZdZdZdZdZdZe	j
dddg Z
‡ fdd„Zdd	„ Zd
d„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zd Zd!Zd"d#„ Zd$d%„ Zd&d'„ Zd(d)„ Zd*d+„ Zd,d-„ Zd.d/„ Z d0d1„ Z!d2d3„ Z"d4d5„ Z#d6d7„ Z$d8d9„ Z%d:d;„ Z&‡  Z'S )<ÚFusedCFuncDefNodea÷  
    This node replaces a function with fused arguments. It deep-copies the
    function for every permutation of fused types, and allocates a new local
    scope for it. It keeps track of the original function in self.node, and
    the entry of the original function in the symbol table is given the
    'fused_cfunction' attribute which points back to us.
    Then when a function lookup occurs (to e.g. call it), the call can be
    dispatched to the right function.

    node    FuncDefNode    the original function
    nodes   [FuncDefNode]  list of copies of node with different specific types
    py_func DefNode        the fused python function subscriptable from
                           Python space
    __signatures__         A DictNode mapping signature specialization strings
                           to PyCFunction nodes
    resulting_fused_function  PyCFunction for the fused DefNode that delegates
                              to specializations
    fused_func_assignment   Assignment of the fused function to the function name
    defaults_tuple          TupleNode of defaults (letting PyCFunctionNode build
                            defaults would result in many different tuples)
    specialized_pycfuncs    List of synthesized pycfunction nodes for the
                            specializations
    code_object             CodeObjectNode shared by all specializations and the
                            fused function

    fused_compound_types    All fused (compound) types (e.g. floating[:])
    NÚ__signatures__Úresulting_fused_functionÚfused_func_assignmentc                s¸   t t| ƒ |j¡ g | _|| _t| jtƒ}|r:|  |¡ n
|  	|¡ xV| jD ]L}|j
jjr^t‚|jjjrlt‚|jjr€|jjr€t‚|sL|jjrL|jjsLt‚qLW | |j
_| jd d … | _d S )N)Úsuperr   Ú__init__ÚposÚnodesÚnodeÚ
isinstancer   Úcopy_defÚ	copy_cdefÚentryÚtypeÚis_fusedÚAssertionErrorÚlocal_scopeÚreturn_typeÚcfunc_declaratorÚoptional_arg_countZop_arg_structÚfused_cfunctionÚstats)Úselfr   ÚenvÚis_defÚn)Ú	__class__© úf/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/Cython/Compiler/FusedNode.pyr   2   s     
zFusedCFuncDefNode.__init__c             C   s  t  dd„ | jjD ƒ¡}|  |¡}t  |¡}|| _| jj|jkrP|j 	| jj¡ x¨|D ] \}}t
 | j¡}| jjj|j_|  |j|¡ | jj |¡|_| |¡ |  |||¡ |  ||| jj||¡ t  |j|¡ d|j_|j|j|jj< |  |¡sVP qVW | j| _| j| j|dd| _dS )zh
        Create a copy of the original def or lambda function for specialized
        versions.
        c             S   s   g | ]}|j jr|j ‘qS r.   )r    r!   )Ú.0Úargr.   r.   r/   ú
<listcomp>U   s    z.FusedCFuncDefNode.copy_def.<locals>.<listcomp>T)r+   N)r   Úuniquer   ÚargsÚ_get_fused_base_typesÚ get_all_specialized_permutationsÚfused_compound_typesr   Úpyfunc_entriesÚremoveÚcopyÚdeepcopyÚ	signatureÚ_specialize_function_argsr$   Ú
specializeÚanalyse_declarationsÚcreate_new_local_scopeÚspecialize_copied_defÚspecialize_entryÚusedÚentriesÚnameÚreplace_fused_typechecksÚorig_py_funcÚmake_fused_cpdefÚpy_func)r)   r*   r7   Úfused_typesÚpermutationsÚcnameÚfused_to_specificÚcopied_noder.   r.   r/   r   O   s0    



zFusedCFuncDefNode.copy_defc             C   s$  | j j ¡ }| j j | _}d| j _|r4|j |j¡ | j j ¡ }|| _	g }xh|D ]^\}}t
 | j ¡}|j |¡}	|j}
|	 |
|¡ xdt|jƒD ]L\}}|
j|jkr’|	 |j¡r’|j| |_|jjsÐ|
j|j_|j}
|
j}	P q’W | |
¡ |	|_|	|
 |
_|	_|
jp | j jjp |jp |
j|
_| j jjrD| j jj|	||d |	j|_|  |||¡ |  |jj|¡ | |¡ |jr¦|j |jj¡ |   |j|| j jj!||¡ |  "|¡sRP qRW y|j #| j j¡}W n" t$k
rì   |j %|¡ Y nX ||j||d …< |r| j&||dd| _n|| _dS )zf
        Create a copy of the original c(p)def function for all specialized
        versions.
        N)Zfused_cnamer   F)r+   )'r   r    r6   rI   rG   r8   r9   r   Úget_fused_typesr7   r:   r;   r>   rB   Ú	enumerateZcfunc_entriesrL   Zsame_as_resolved_typeÚ
func_cnameÚappendrC   Zdefined_in_pxdZis_c_class_scopeZ
is_cmethodr%   r&   Zdeclare_optional_arg_structr$   r@   r=   r4   Zdeclare_cpdef_wrapperrA   Úas_variablerF   ÚindexÚ
ValueErrorÚextendrH   )r)   r*   rK   rG   rJ   Znew_cfunc_entriesrL   rM   rN   r    r   ÚiZ
orig_entryZcindexr.   r.   r/   r   x   sh    




zFusedCFuncDefNode.copy_cdefc             C   s*   g }t ƒ }x|D ]}|j||d qW |S )zq
        Get a list of unique basic fused types, from a list of
        (possibly) compound fused types.
        )ÚresultÚseen)ÚsetrO   )r)   r7   Z
base_typesrY   Ú
fused_typer.   r.   r/   r5   Î   s
    
z'FusedCFuncDefNode._get_fused_base_typesc             C   s>   x8|D ]0}|j jr|j  |¡|_ |j jr|j  |j¡ qW d S )N)r    r!   r>   Úis_memoryviewsliceZvalidate_memslice_dtyper   )r)   r4   rM   r1   r.   r.   r/   r=   Ù   s
    
z+FusedCFuncDefNode._specialize_function_argsc             C   s(   |  |¡ ||j_d|_| j |¡ dS )a¥  
        Create a new local scope for the copied node and append it to
        self.nodes. A new local scope is needed because the arguments with the
        fused types are already in the local scope, and we need the specialized
        entries created after analyse_declarations on each specialized version
        of the (CFunc)DefNode.
        f2s is a dict mapping each fused type to its specialized version
        FN)Zcreate_local_scoper#   rM   Zhas_fused_argumentsr   rR   )r)   r   r*   Úf2sr.   r.   r/   r@   à   s    	
z(FusedCFuncDefNode.create_new_local_scopec                sT   |   |¡}‡ fdd„|D ƒ}d |¡|_t ||jj¡|j_|j|j_|j|j_dS )zwSpecialize the copy of a DefNode given the copied node,
        the specialization cname and the original DefNode entryc                s   g | ]}t  |ˆ ¡‘qS r.   )r   Zspecialization_signature_string)r0   r[   )r]   r.   r/   r2   ö   s   z;FusedCFuncDefNode.specialize_copied_def.<locals>.<listcomp>ú|N)	r5   ÚjoinÚspecialized_signature_stringr   Zget_fused_cnamer   Úpymethdef_cnameÚdocÚ	doc_cname)r)   r   rL   Zpy_entryr]   r7   rJ   Ztype_stringsr.   )r]   r/   rA   ñ   s    


z'FusedCFuncDefNode.specialize_copied_defc             C   s,   t j}t |j¡}||ƒ t j|kr(dS dS )zã
        Branch-prune fused type checks like

            if fused_t is int:
                ...

        Returns whether an error was issued and whether we should stop in
        in order to prevent a flood of errors.
        FT)r	   Ú
num_errorsr   ZReplaceFusedTypeChecksr#   )r)   rN   rd   Z	transformr.   r.   r/   rF     s    

z*FusedCFuncDefNode.replace_fused_typechecksc             C   s2   x,|D ]$}|j j| ¡ |jd | d¡ qW dS )zl
        Generate Cython code for instance checks, matching an object to
        specialized types.
        )Úpy_type_nameÚspecialized_type_namez£
                    if isinstance(arg, {{py_type_name}}):
                        dest_sig[{{dest_sig_idx}}] = '{{specialized_type_name}}'; break
                N)ÚcontextÚupdatere   Úspecialization_stringÚ	put_chunk)r)   Únormal_typesÚpyx_coder*   Úspecialized_typer.   r.   r/   Ú_fused_instance_checks  s    

z(FusedCFuncDefNode._fused_instance_checksc             C   s   |j rd| S t|ƒ dd¡S )Nz	___pyx_%sú Ú_)Ú
is_typedefÚstrÚreplace)r)   Údtyper.   r.   r/   Ú_dtype_name&  s    zFusedCFuncDefNode._dtype_namec             C   s   |j r|  |¡S t|ƒS )N)rq   ru   rr   )r)   rt   r.   r.   r/   Ú_dtype_type+  s    
zFusedCFuncDefNode._dtype_typec             C   s   |j r
dS d|  |¡ S d S )Nzsizeof(void *)z
sizeof(%s))Zis_pyobjectrv   )r)   rt   r.   r.   r/   Ú_sizeof_dtype0  s    zFusedCFuncDefNode._sizeof_dtypec             C   sœ   |  d¡r&| d¡ | d¡ | ¡  |  d¡rL| d¡ | d¡ | ¡  |  d¡rr| d¡ | d¡ | ¡  |  d¡r˜| d¡ | d	¡ | ¡  d
S )z?Setup some common cases to match dtypes against specializationszif kind in b'iu':ÚpassÚ	dtype_intzelif kind == b'f':Údtype_floatzelif kind == b'c':Údtype_complexzelif kind == b'O':Zdtype_objectN)ÚindenterÚputlnÚnamed_insertion_pointÚdedent)r)   rl   r.   r.   r/   Ú%_buffer_check_numpy_dtype_setup_cases6  s     











z7FusedCFuncDefNode._buffer_check_numpy_dtype_setup_casesz8dest_sig[{{dest_sig_idx}}] = '{{specialized_type_name}}'z!dest_sig[{{dest_sig_idx}}] = Nonec             C   sì   |   |¡ xÜ|| D ]Ð}|}|jr(|j}|j}|jj|  |¡d d|  |¡ ||jd |j	|j
f|j|jf|j|jfg}xh|D ]`\}}	|r€d|jf }
|j	r¦|
d7 }
|jr´|
d7 }
|	 d|
 ¡r€|	 | j¡ |	 d¡ |	 ¡  q€W qW d	S )
zO
        Match a numpy dtype object to the individual specializations.
        z == itemsizez!not (%s_is_signed ^ dtype_signed))Zitemsize_matchZsigned_matchrt   rf   z3{{itemsize_match}} and (<Py_ssize_t>arg.ndim) == %dz and {{signed_match}}z and arg_is_pythran_compatiblezif %s:ÚbreakN)r€   Úis_pythran_exprÚ
org_bufferrt   rg   rh   rw   ru   ri   Úis_intry   Zis_floatrz   Ú
is_complexr{   Úndimr|   r}   Úmatchr   )r)   rl   Zspecialized_buffer_typesÚpythran_typesrm   Z
final_typert   ZdtypesZdtype_categoryZ
codewriterZcondr.   r.   r/   Ú_buffer_check_numpy_dtypeN  s4    





z+FusedCFuncDefNode._buffer_check_numpy_dtypec             C   s~   |j }|jrdg|j }n|j}t ||¡}| |¡ |jj|j	|d | 
d¡ |jj|j|  |¡d | d| j ¡ dS )zô
        For each specialized type, try to coerce the object to a memoryview
        slice of that type. This means obtaining a buffer and parsing the
        format string.
        TODO: separate buffer acquisition from format parsing
        )ÚdirectZstrided)Zcoerce_from_py_funcrt   z;{{memviewslice_cname}} {{coerce_from_py_func}}(object, int))rf   Zsizeof_dtypeaæ  
                # try {{dtype}}
                if itemsize == -1 or itemsize == {{sizeof_dtype}}:
                    memslice = {{coerce_from_py_func}}(arg, 0)
                    if memslice.memview:
                        __PYX_XDEC_MEMVIEW(&memslice, 1)
                        # print 'found a match for the buffer through format parsing'
                        %s
                        break
                    else:
                        __pyx_PyErr_Clear()
            N)rt   Ú	is_bufferr†   Úaxesr   ZMemoryViewSliceTypeZcreate_from_py_utility_coderg   rh   Zfrom_py_functionr}   ri   rw   rj   r‡   )r)   rl   Ú	decl_coderm   r*   rt   rŒ   Zmemslice_typer.   r.   r/   Ú!_buffer_parse_format_string_checku  s     
z3FusedCFuncDefNode._buffer_parse_format_string_checkc             C   s†   |  d|rdnd d |rdnd d ¡ | d¡ |rB|  d¡ | d	¡ |  |||¡ | d¡ x|D ]}|  ||||¡ qjW d
S )a^  
        Generate Cython code to match objects to buffer specializations.
        First try to get a numpy dtype object and match it against the individual
        specializations. If that fails, try naively to coerce the object
        to each specialization, which obtains the buffer each time and tries
        to match the format string.
        z
                z!arg_is_pythran_compatible = FalseÚ zœ
                if ndarray is not None:
                    if isinstance(arg, ndarray):
                        dtype = arg.dtype
                        z arg_is_pythran_compatible = TrueaC  
                    elif __pyx_memoryview_check(arg):
                        arg_base = arg.base
                        if isinstance(arg_base, ndarray):
                            dtype = arg_base.dtype
                        else:
                            dtype = None
                    else:
                        dtype = None

                    itemsize = -1
                    if dtype is not None:
                        itemsize = dtype.itemsize
                        kind = ord(dtype.kind)
                        dtype_signed = kind == 'i'
            r   aS  
                        # Pythran only supports the endianness of the current compiler
                        byteorder = dtype.byteorder
                        if byteorder == "<" and not __Pyx_Is_Little_Endian():
                            arg_is_pythran_compatible = False
                        elif byteorder == ">" and __Pyx_Is_Little_Endian():
                            arg_is_pythran_compatible = False
                        if arg_is_pythran_compatible:
                            cur_stride = itemsize
                            shape = arg.shape
                            strides = arg.strides
                            for i in range(arg.ndim-1, -1, -1):
                                if (<Py_ssize_t>strides[i]) != cur_stride:
                                    arg_is_pythran_compatible = False
                                    break
                                cur_stride *= <Py_ssize_t> shape[i]
                            else:
                                arg_is_pythran_compatible = not (arg.flags.f_contiguous and (<Py_ssize_t>arg.ndim) > 1)
                Znumpy_dtype_checksN)rj   Úindentr~   r‰   r   rŽ   )r)   Úbuffer_typesrˆ   rl   r   r*   rm   r.   r.   r/   Ú_buffer_checks  s    	



z FusedCFuncDefNode._buffer_checksc       
      C   sØ   |  d¡ |j  d¡ |r&|j  d¡ |j  d¡ tƒ }tƒ }x”|D ]Œ}|j}|  |¡}	|jrŒ|	|krŒ| |	¡ | d| 	¡ |	| 
¡ f ¡ |jjrDt|ƒ|krD| t|ƒ¡ |jj|	|  |¡d |j  d¡ qDW dS )	zr
        If we have any buffer specializations, write out some variable
        declarations and imports.
        zì
                ctypedef struct {{memviewslice_cname}}:
                    void *memview

                void __PYX_XDEC_MEMVIEW({{memviewslice_cname}} *, int have_gil)
                bint __pyx_memoryview_check(object)
            zÐ
                cdef {{memviewslice_cname}} memslice
                cdef Py_ssize_t itemsize
                cdef bint dtype_signed
                cdef char kind

                itemsize = -1
            zl
                cdef bint arg_is_pythran_compatible
                cdef Py_ssize_t cur_stride
            zq
                cdef type ndarray
                ndarray = __Pyx_ImportNumPyArrayTypeIfAvailable()
            zctypedef %s %s "%s")Ú
dtype_nameZ
dtype_typez­
                            cdef bint {{dtype_name}}_is_signed
                            {{dtype_name}}_is_signed = not (<{{dtype_type}}> -1 > 0)
                        N)rj   Úlocal_variable_declarationsÚimportsrZ   rt   ru   rq   Úaddr}   ÚresolveZempty_declaration_coder„   rr   rg   rh   rv   )
r)   rl   r   Úall_buffer_typesrˆ   Zseen_typedefsZseen_int_dtypesZbuffer_typert   r“   r.   r.   r/   Ú_buffer_declarationsÚ  s6    



z&FusedCFuncDefNode._buffer_declarationsc       
      C   sª   t  |j¡}| ¡  tƒ }g g g   }}}d}xn|D ]f}| ¡ }	|	rr|	|krNq4| |	¡ |	dkrfd}qš| |¡ q4|jr„| |¡ q4|j	s|j
r4| |¡ q4W ||||fS )zV
        Specialize fused types and split into normal types and buffer types.
        FÚobjectT)r   Zget_specialized_typesr    ÚsortrZ   re   r–   rR   r‚   r‹   r\   )
r)   r1   Zspecialized_typesZseen_py_type_namesrk   r‘   rˆ   Úhas_object_fallbackrm   re   r.   r.   r/   Ú_split_fused_types  s&    

z$FusedCFuncDefNode._split_fused_typesc             C   s   |  d¡ d S )Na“  
                # PROCESSING ARGUMENT {{arg_tuple_idx}}
                if {{arg_tuple_idx}} < len(<tuple>args):
                    arg = (<tuple>args)[{{arg_tuple_idx}}]
                elif kwargs is not None and '{{arg.name}}' in <dict>kwargs:
                    arg = (<dict>kwargs)['{{arg.name}}']
                else:
                {{if arg.default}}
                    arg = (<tuple>defaults)[{{default_idx}}]
                {{else}}
                    {{if arg_tuple_idx < min_positional_args}}
                        raise TypeError("Expected at least %d argument%s, got %d" % (
                            {{min_positional_args}}, {{'"s"' if min_positional_args != 1 else '""'}}, len(<tuple>args)))
                    {{else}}
                        raise TypeError("Missing keyword-only argument: '%s'" % "{{arg.default}}")
                    {{endif}}
                {{endif}}
            )rj   )r)   rl   r.   r.   r/   Ú_unpack_argument2  s    z"FusedCFuncDefNode._unpack_argumentc             C   s0  ddl m}m}m} |  dd„ | jjD ƒ¡}tj| jjt	|ƒ|rP| jj
| jj ntdd„ | jjD ƒƒ|jjdœ}|j|d}	|j|d}
|
 d	¡ |
 ¡  |	 d
¡ |	 ¡  |	 d¡ |	 d¡ |	 d¡ d}d}tƒ }tƒ }x^t| jjƒD ]L\}}|jjr*|j ¡ }t	|ƒdkr"tdƒ‚|d }|jjr.||kr.| |¡ |j||||d |  |¡\}}}}|  |	¡ |	 d¡r|r–|  ||	|¡ |s¢|rÈ|  |j !dd¡¡ |  "|||	|
|¡ |rê|	j#jdd |	 $| j%¡ n|	 $| j&¡ |	 $d¡ |	 '¡  |d7 }| |¡ | dd„ |D ƒ¡ |j(rî|d7 }qîW |r~|  )|	|
||¡ |  |j !dd¡¡ |  |j !dd¡¡ |	 d¡ |	 *¡ }ddl+m,} |j|d|ƒ gd}| -| jj.¡|j/ƒ}| 0|
 *¡ | 1¡ ¡ ||_2| 3|¡ |j4d }|j2| _5t6| jt7ƒr| j8d d … |_9nd!d„ | j8D ƒ|_9|S )"a!  
        This creates the function that is indexable from Python and does
        runtime dispatch based on the argument types. The function gets the
        arg tuple and kwargs dict (or None) and the defaults tuple
        as arguments from the Binding Fused Function's tp_call.
        r   )ÚTreeFragmentÚCodeÚUtilityCodec             S   s   g | ]}|j jr|j ‘qS r.   )r    r!   )r0   r1   r.   r.   r/   r2   Q  s    z6FusedCFuncDefNode.make_fused_cpdef.<locals>.<listcomp>c             s   s   | ]}|j d krdV  qd S )Nr   )Údefault)r0   r1   r.   r.   r/   ú	<genexpr>Z  s    z5FusedCFuncDefNode.make_fused_cpdef.<locals>.<genexpr>)Úmemviewslice_cnameZ	func_argsZn_fusedZmin_positional_argsrE   )rg   zß
                cdef extern from *:
                    void __pyx_PyErr_Clear "PyErr_Clear" ()
                    type __Pyx_ImportNumPyArrayTypeIfAvailable()
                    int __Pyx_Is_Little_Endian()
            aå  
                def __pyx_fused_cpdef(signatures, args, kwargs, defaults):
                    # FIXME: use a typed signature - currently fails badly because
                    #        default arguments inherit the types we specify here!

                    dest_sig = [None] * {{n_fused}}

                    if kwargs is not None and not kwargs:
                        kwargs = None

                    cdef Py_ssize_t i

                    # instance check body
            r•   Z	func_defsr”   r   zODetermination of more than one fused base type per argument is not implemented.)Zarg_tuple_idxr1   Zdest_sig_idxÚdefault_idxzwhile 1:ZIsLittleEndianzModuleSetupCode.crš   )rf   r   c             s   s   | ]}|j V  qd S )N)rƒ   )r0   Útyr.   r.   r/   r£   ¨  s    ÚImportzImportExport.cZImportNumPyArraya¿  
                candidates = []
                for sig in <dict>signatures:
                    match_found = False
                    src_sig = sig.strip('()').split('|')
                    for i in range(len(dest_sig)):
                        dst_type = dest_sig[i]
                        if dst_type is not None:
                            if src_sig[i] == dst_type:
                                match_found = True
                            else:
                                match_found = False
                                break

                    if match_found:
                        candidates.append(sig)

                if not candidates:
                    raise TypeError("No matching signature found")
                elif len(candidates) > 1:
                    raise TypeError("Function call with ambiguous argument types")
                else:
                    return (<dict>signatures)[candidates[0]]
            )ÚConstantFoldingÚmodule)ÚlevelZpipelineéÿÿÿÿNc             S   s   g | ]
}|j ‘qS r.   )rI   )r0   r,   r.   r.   r/   r2   Þ  s    ):r   rŸ   r    r¡   r5   r   r4   r   r¤   ÚlenZnum_required_argsZnum_required_kw_argsÚsumr   rE   ZPyxCodeWriterrj   r   r~   r   rZ   rP   r    r!   rO   ÚNotImplementedErrorr–   rh   r   rž   r|   rn   Zuse_utility_codeZload_cachedr’   rg   r}   r‡   Úno_matchr   r¢   r™   ÚgetvalueZOptimizer¨   ZSetPosTransformr   ÚrootZdeclare_declarations_in_scopeZglobal_scopeÚscoper?   r(   Zfragment_scoper   r   r   Zspecialized_cpdefs)r)   rG   r*   r+   rŸ   r    r¡   rJ   rg   rl   r   Zfused_indexr¥   r˜   Zseen_fused_typesrW   r1   Zarg_fused_typesr[   rk   r‘   rˆ   rœ   Zfragment_coder¨   ÚfragmentÚastrI   r.   r.   r/   rH   G  sš    










z"FusedCFuncDefNode.make_fused_cpdefc             C   sæ   d}| j j}x"|D ]}t||t| jj|ƒƒ qW | jj| j _| jj| j _|j dd ¡ t	| j
tƒrp||j|j< n||j|j _|j |¡ | | j j_x6| jD ],}t	| j
tƒr¶| j |_qœ| j |j _||j_qœW |  ¡  | j | j¡ d S )N)
rE   r   rL   rQ   Zpyfunc_cnamera   rb   rc   Z	is_memberr²   Z__pyx_fused_cpdef)rI   r   ÚsetattrÚgetattrrG   rE   rb   rD   Úpopr   r   r   rS   r8   rR   r'   r   Zfused_py_funcÚsynthesize_defnodesr(   r   )r)   r*   Zcopy_attributesr   Úattrr   r.   r.   r/   Úupdate_fused_defnode_entryâ  s(    



z,FusedCFuncDefNode.update_fused_defnode_entryc             C   s  x@| j D ]6}x0| ¡ D ]$}x|jD ]}|jr"| |¡ q"W qW qW | jr€| j |¡| _| j |¡| _| j |¡| _| j	 |¡| _	g  | _
}x@| jjD ]4}|jr¾|j |¡|_| t|jƒ¡ q”| d¡ q”W xnt| jƒD ]`\}}| |¡ }| j|< t|tƒrØx8t|j|ƒD ](\}}	|	dk	rt|	ƒ |j|¡|_qW qØW | jrþdd„ |D ƒ}
t| j|
d| _| jj|dd |¡| _t| jƒ| _t| jd jƒ| _| jj}t| jƒ|_t| jƒ|_xDt| jƒD ]6\}}t| jƒ|_| |¡ }| j|< t| jƒ|_qÄW | S )z‘
        Analyse the expressions. Take care to only evaluate default arguments
        once and clone the result for all specializations
        Nc             S   s   g | ]}|rt |ƒ‘qS r.   )r
   )r0   r¢   r.   r.   r/   r2   '  s    z9FusedCFuncDefNode.analyse_expressions.<locals>.<listcomp>)r4   T)Zskip_childrenr   ) r7   rO   Útypesr…   Zcreate_declaration_utility_coderI   r   Úanalyse_expressionsr   r   Údefaultsr   r4   r¢   rR   r   rP   r(   r   r   Úzipr
   Z	coerce_tor    r   r   Údefaults_tupleZanalyse_typesZcoerce_to_pyobjectÚspecialized_pycfuncsÚcode_objectr1   )r)   r*   Zfused_compound_typer[   Zspecialization_typer½   r1   rW   Ústatr¢   r4   Z
fused_funcZpycfuncr.   r.   r/   r¼     sH    


z%FusedCFuncDefNode.analyse_expressionsc             C   sŽ   t | jd tƒr"dd„ | jD ƒ}n| j}dd„ |D ƒ}dd„ t||ƒD ƒ}dd„ |D ƒ}tj | jt||ƒ¡| _|| _	x|D ]
}d|_
q|W dS )	zT
        Create the __signatures__ dict of PyCFunctionNode specializations.
        r   c             S   s   g | ]
}|j ‘qS r.   )rI   )r0   r   r.   r.   r/   r2   <  s    z9FusedCFuncDefNode.synthesize_defnodes.<locals>.<listcomp>c             S   s   g | ]}t  |j¡‘qS r.   )r   ZEncodedStringr`   )r0   r   r.   r.   r/   r2   @  s   c             S   s    g | ]\}}t j|j|d ‘qS ))Úvalue)r   Z
StringNoder   )r0   r   Úsigr.   r.   r/   r2   B  s   c             S   s   g | ]}t jj|d d‘qS )T)Zbinding)r   ZPyCFunctionNodeZfrom_defnode)r0   r   r.   r.   r/   r2   D  s   TN)r   r   r   r¾   r   ZDictNodeZ
from_pairsr   r   rÀ   Zis_specialization)r)   r   Z
signaturesÚkeysÚvaluesZpycfuncnoder.   r.   r/   r¸   7  s    
z%FusedCFuncDefNode.synthesize_defnodesc             C   sZ   | j rd| j _| j ||¡ x8| jD ].}t|tƒr$|jjr$| 	|j
¡ | ||¡ q$W d S )NT)rI   Zpymethdef_requiredr   Úgenerate_function_definitionsr(   r   r   r   rC   Úmark_posr   )r)   r*   ÚcoderÂ   r.   r.   r/   rÇ   M  s    z/FusedCFuncDefNode.generate_function_definitionsc             C   s`  x | j D ]}|d k	r| |¡ qW | jr@| j |¡ | j |¡ x<| jD ]2}| |j¡ t|t	j
ƒrp| |¡ qH| |¡ qHW | jr,| j |¡ | d| j ¡ | j ¡ f ¡ | | j ¡ ¡ | j |¡ | j |¡ | j |¡ | j |¡ | j |¡ | j |¡ | j |¡ | j |¡ | j |¡ x.| j D ]$}|d k	r4| |¡ | |¡ q4W d S )Nz8((__pyx_FusedFunctionObject *) %s)->__signatures__ = %s;)r½   Zgenerate_evaluation_coderI   r¿   rÁ   r(   rÈ   r   r   r   ZExprNodeÚgenerate_execution_coder   r   r}   rX   Zput_giverefZgenerate_post_assignment_codeZ
free_tempsr   Zgenerate_disposal_code)r)   rÉ   r¢   rÂ   r.   r.   r/   rÊ   W  s>    

z)FusedCFuncDefNode.generate_execution_codec             C   s   x| j D ]}| |¡ qW d S )N)r(   Úannotate)r)   rÉ   rÂ   r.   r.   r/   rË   ƒ  s    zFusedCFuncDefNode.annotate)(Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   r¿   Z
decoratorsr   Zchild_attrsr   r   r   r5   r=   r@   rA   rF   rn   ru   rv   rw   r€   r‡   r¯   r‰   rŽ   r’   r™   r   rž   rH   rº   r¼   r¸   rÇ   rÊ   rË   Ú__classcell__r.   r.   )r-   r/   r      sJ   )V'(=; #2
,r   )Ú
__future__r   r:   r   r   r   r   r   r   r	   r
   r   r   ZNodesr   r   r   r   ZUtilsr   r   r.   r.   r.   r/   Ú<module>   s    