o
    @a                      @   s.  d 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	m
Z
mZ ddlmZmZ ddlmZmZmZmZ ddlmZmZmZmZmZ ddlmZmZmZmZ dd	lmZmZmZmZm Z  dd
lm!Z!m"Z"m#Z#m$Z$m%Z%m&Z& ddl'm(Z( ddl)m*Z* ddl+m,Z, ddl-m.Z.m/Z/ ddl-m0Z0 ddl1m2Z2m3Z3 ddl4m5Z5 ddl6m7Z7m8Z8m9Z9m:Z:m;Z; ddl6m<Z<m=Z= ddl>m?Z?m@Z@ ddlAmBZBmCZC ddlDZEddlFZFddlGmHZH ddlIZIG dd de*ZJd,ddZKdd ZLG dd dZMd d! ZN	d-d"d#ZO	d,d$d%ZPG d&d' d'eEjQZRG d(d) d)eRZSG d*d+ d+e*ZTdS ).z~
This module contains all pythran backends.
    * Cxx dumps the AST into C++ code
    * Python dumps the AST into Python code
    )LocalNodeDeclarationsGlobalDeclarationsScope)YieldPoints
IsAssigned
ASTMatcherAST_any)RangeValuesPureExpressionsDependencies)
Immediates	Ancestors)TemplateInclude	NamespaceCompilationUnit)	StatementBlockAnnotatedStatementTypedefLabel)ValueFunctionDeclarationEmptyStatementNop)FunctionBodyLineReturnStatementStructAssign)ForWhile	TryExceptExceptHandlerIfAutoFor)OMPDirective)Backend)PythranSyntaxError)operator_to_lambdaupdate_operator_to_lambda)pythran_ward)PYTYPE_TO_CTYPE_TABLETYPE_TO_SUFFIX)Types)attr_to_pathpushpopcxxidisstrisnum)
isextsliceispowi)metadataunparse)isnanisinfN)reducec                       s(   e Zd ZdZ fddZdd Z  ZS )Pythona  
    Produces a Python representation of the AST.

    >>> import gast as ast, pythran.passmanager as passmanager
    >>> node = ast.parse("print('hello world')")
    >>> pm = passmanager.PassManager('test')
    >>> print(pm.dump(Python, node))
    print('hello world')
    c                    s   d| _ tt|   d S N )resultsuperr;   __init__self	__class__ 1/usr/lib/python3/dist-packages/pythran/backend.pyr@   -   s   zPython.__init__c                 C   s"   t  }t|| | | _d S N)ioStringIOr7   ZUnparsergetvaluer>   )rB   nodeoutputrE   rE   rF   visit1   s   zPython.visit)__name__
__module____qualname____doc__r@   rM   __classcell__rE   rE   rC   rF   r;   "   s    
r;   c                 C   s4   |s	d gt | }|rtdd t||D | S | S )Nc                 S   s*   g | ]\}}d  ||rd |ndqS )ztypename {0} {1}= {0}r=   format).0tdrE   rE   rF   
<listcomp><   s    ztemplatize.<locals>.<listcomp>)lenr   zip)rK   typesZdefault_typesrE   rE   rF   
templatize7   s   r]   c                    s    fdd}|S )a  
    Decorator for loop node (For and While) to handle "else" branching.

    Decorated node will save flags for a goto statement used instead of usual
    break and add this flag at the end of the else statements.

    Examples
    --------
    >> for i in range(12):
    >>     if i == 5:
    >>         break
    >> else:
    >>     ... some code ...

    Becomes

    >> for(type i : range(12))
    >>     if(i==5)
    >>         goto __no_breaking0;
    >> ... some code ...
    >> __no_breaking0;
    c                    s   |j s!t jd  |}W d   |S 1 sw   Y  |S dt|}t j|  |}W d   n1 s>w   Y   fdd|j D }| jv rXt|g}ng }t|g| | S )zw
        New decorate function.

        It push the breaking flag, run the visitor and add "else" statements.
        Nz__no_breaking{0}c                       g | ]}  |qS rE   rM   rV   stmtrA   rE   rF   rY   j       z2cxx_loop.<locals>.loop_visitor.<locals>.<listcomp>)orelser0   break_handlersrU   id
used_breakr   r   )rB   rK   resZbreak_handlerrc   Zorelse_labelr_   rA   rF   loop_visitorZ   s    

zcxx_loop.<locals>.loop_visitorrE   )rM   rh   rE   r_   rF   cxx_loopC   s   ri   c                   @   s&   e Zd ZdddZdd Zdd ZdS )	CachedTypeVisitorNc                 C   sL   |d u rt  | _t  | _t  | _d S |j | _|j | _|j | _d S rG   )dictcachercachemappingcopy)rB   otherrE   rE   rF   r@   u   s   zCachedTypeVisitor.__init__c                 C   s   || j vr=|| }|| j vr=|| jv r+| j | j|  | j |< | j| j|  | j|< n|| j|< t| j | j |< || j|< d| j | S )Nz	__type{0})rn   generaterm   rl   rZ   rU   )rB   rK   rW   rE   rE   rF   __call__   s   





zCachedTypeVisitor.__call__c                 C   sl   t | j dd d}t }t }|D ] \}}||vr3dt| }|tt| j	| | |
| q|S )Nc                 S      | d S )N   rE   xrE   rE   rF   <lambda>       z,CachedTypeVisitor.typedefs.<locals>.<lambda>keyZ__type)sortedrn   itemslistsetstrappendr   r   rl   add)rB   ZkvLZvisitedkvtypenamerE   rE   rF   typedefs   s   
zCachedTypeVisitor.typedefsrG   )rN   rO   rP   r@   rr   r   rE   rE   rE   rF   rj   s   s    

rj   c                 C   s   | rd | S dS )NrS   r=   rT   )rX   rE   rE   rF   make_default   s   r   c                 C   s   |d u rd gt | }|d u rg }t }t |jjt |jj }	tt|||D ]'\}
\}}}t| ts8|
|	kr;d}nd}t|| d	|t
|}|| q(tt|||g|R  S )Nr=   z&&{0}{1})rZ   r}   argsdefaults	enumerater[   
isinstanceCxxGeneratorr   rU   r   r   r   )rB   rK   rtypenameftypesfargsr   Z
attributesZ	argumentsZfirst_defaultirW   arX   Z
rvalue_refargumentrE   rE   rF   make_function_declaration   s   r   c              	   C   s   t | ||||||dgS )Nconst)r   )rB   rK   r   r   r   r   r   rE   rE   rF   make_const_function_declaration   s   r   c                       s  e Zd ZdZdd Zdd Zdd Zdd	 Z fd
dZdkd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'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zed1d2 Zed3d4 Zd5d6 Zd7d8 Zd9d: Z d;d< Z!d=d> Z"d?d@ Z#dAdB Z$dCdD Z%dEdF Z&dGdH Z'dIdJ Z(dKdL Z)dMdN Z*dOdP Z+dQdR Z,dSdT Z-dUdV Z.dWdX Z/dYdZ Z0d[d\ Z1d]d^ Z2d_d` Z3dadb Z4dcdd Z5dedf Z6dgdh Z7didj Z8  Z9S )lCxxFunctionaz  
    Attributes
    ----------
    ldecls : {str}
        set of local declarations.
    break_handler : [str]
        It contains flags for goto statements to jump on break in case of
        orelse statement in loop. None means there are no orelse statement so
        no jump are requiered.
        (else in loop means : don't execute if loop is terminated with a break)
    c                 C   s&   || _ g | _t | _d| _t | _dS z4 Basic initialiser gathering analysis informations. N)parentrd   r~   rf   ldeclsopenmp_deps)rB   r   rE   rE   rF   r@      s
   zCxxFunction.__init__c                 C   s   t | j|S rG   )getattrr   )rB   attrrE   rE   rF   __getattr__   s   zCxxFunction.__getattr__c           	      G   sp   | j | |}|| j}|s|S g }|D ]}| |}td||}|| q| j| t	||g S )z
        Declare variable local to node and insert declaration before.

        Not possible for function yielding values.
        {} {})
scope
differencer   typeofr   rU   r   r   difference_updater   )	rB   rK   node_visitedskippedZ
local_varsZlocals_visitedZvarnameZvartypeZdeclrE   rE   rF   process_locals   s   
zCxxFunction.process_localsc                 C   s4   | j dd |jD  | j dd |jD  d S )Nc                 s       | ]}|j V  qd S rG   re   rV   rX   rE   rE   rF   	<genexpr>       z1CxxFunction.visit_OMPDirective.<locals>.<genexpr>c                 s   r   rG   r   r   rE   rE   rF   r      r   )r   updateprivate_depsshared_depsrB   rK   rE   rE   rF   visit_OMPDirective   s   zCxxFunction.visit_OMPDirectivec                    s   t | | tt| |S rG   )r6   rM   r?   r   r   rC   rE   rF   rM      s   zCxxFunction.visitNc                    sl   t |t}|r4t }|D ]} fdd|jD |_|| q|du r+t||}|S t|| |||< |S )z
        Add OpenMP pragma on the correct stmt in the correct order.

        stmt may be a list. On this case, index have to be specify to add
        OpenMP on the correct statement.
        c                    r^   rE   r_   )rV   ZdeprA   rE   rF   rY      rb   z8CxxFunction.process_omp_attachements.<locals>.<listcomp>N)r6   getr&   r}   depsr   r   )rB   rK   ra   indexZomp_directivesZ
directives	directiverE   rA   rF   process_omp_attachements   s   
z$CxxFunction.process_omp_attachementsc                 C   s,   t |tr| | j| S | j| | jS rG   )r   r   r   local_namesr\   rq   lctxr   rE   rE   rF   r      s   
zCxxFunction.typeofc                    s   |j j }dd |D }dd tt|D }t t|}dd |D  _ jdd |D  t  _	dd |D  _
 fd	d|jD }|||fS )
Nc                 S   s   g | ]}t |jqS rE   )r1   re   rV   argrE   rE   rF   rY     rb   z;CxxFunction.prepare_functiondef_context.<locals>.<listcomp>c                 S   s   g | ]}d t | qS )Zargument_type)r   )rV   r   rE   rE   rF   rY         c                 S      i | ]}|j |qS rE   r   )rV   ZsymrE   rE   rF   
<dictcomp>      z;CxxFunction.prepare_functiondef_context.<locals>.<dictcomp>c                 S   r   rE   r   r   rE   rE   rF   r     r   c                 S      h | ]}|j qS rE   r   rV   nrE   rE   rF   	<setcomp>      z:CxxFunction.prepare_functiondef_context.<locals>.<setcomp>c                    r^   rE   r_   r`   rA   rE   rF   rY     rb   )r   rangerZ   r~   gatherr   r   r   rj   r   r   body)rB   rK   r   formal_argsformal_typesZlocal_declsr   rE   rA   rF   prepare_functiondef_context  s   
z'CxxFunction.prepare_functiondef_contextc                    s   d gt |jjt |jj   fdd|jjD  }d gt |jjt |jj   fdd|jjD  } j| d }ttdd}| jv rNttddnt }|||||fS )Nc                    r^   rE   r_   r   rA   rE   rF   rY     rb   z-CxxFunction.prepare_types.<locals>.<listcomp>c                    s   g | ]} j | qS rE   )r\   r   rA   rE   rF   rY     rb   r   voidcallableZpure)rZ   r   r   r\   r   r   pure_expressionsr   )rB   rK   	dflt_argv	dflt_argtresult_typecallable_type	pure_typerE   rA   rF   prepare_types  s   zCxxFunction.prepare_typesc              	      sl  t |j_|}|\}}}|}|\}}}}	}
d|r(dd|nd}dj|}tt|d|d|||||t	 g}t|d|dj||}t
j  fd	d
jD }  }tt||t|| | }t
   fdd
j| d D tt| dg }  | }ttd|||g}tj|	|
g| | }|g|gfS )Nz	type{0}::<{0}>, r=   z{0}::{1}ztypename {0}result_type
operator(){0}::operator()c                    s2   g | ]}t d jj|   t|qS z{0} {1})r   rU   r\   r   rq   r1   rV   r   ctxrB   rE   rF   rY   I  s
    
z1CxxFunction.visit_FunctionDef.<locals>.<listcomp>c                    "   g | ]}t t| |jqS rE   r   r   rq   r   rV   rW   r   rE   rF   rY   W      rt   r   type)r1   r   fnamer   r   rU   joinr]   r   r   rj   r   r   r   r   r   r\   r   r   rq   r   )rB   rK   tmpoperator_bodyr   r   r   r   r   r   r   ZfscopeZffscopeoperator_declarationoperator_signatureZoperator_local_declarationsZdependent_typedefsoperator_definitionextra_typedefsZreturn_declaration	topstructrE   r   rF   visit_FunctionDef'  s   





zCxxFunction.visit_FunctionDefc                 C   sV   |  |j}t|tjr!d| j}ttd| |t	dg}nt	|}| 
||S )Nztypename {}::type::result_typezstatic %s tmp_globalZ
tmp_global)rM   valuer6   r   ZStaticReturnrU   r   r   r   r   r   )rB   rK   r   r   ra   rE   rE   rF   visit_Returnl  s   zCxxFunction.visit_Returnc                 C      t  S rG   r   rB   _rE   rE   rF   visit_Delete{     zCxxFunction.visit_Deletec              	      sx  t dd |jD std| |j} fdd|jD }d|}t|dkoFt|jd tj	oF|jd j
 j| v oF|jd j
 jv}|r jd	d |jD   j|jd   rld
 |jd |}nEt j|jd   jjjrd
 jj jjd||}n#t j|jd   jjjsJ d
 jj jjd||}t||} ||S )ar  
        Create Assign node for final Cxx representation.

        It tries to handle multi assignment like:

        >> a = b = c = 2

        If only one local variable is assigned, typing is added:

        >> int a = 2;

        TODO: Handle case of multi-assignement for some local variables.

        Finally, process OpenMP clause like #pragma omp atomic
        c                 s   s"    | ]}t |tjtjfV  qd S rG   )r   astNameZ	Subscriptr   rE   rE   rF   r     s    z+CxxFunction.visit_Assign.<locals>.<genexpr>z+Must assign to an identifier or a subscriptc                    r^   rE   r_   r   rA   rE   rF   rY     rb   z,CxxFunction.visit_Assign.<locals>.<listcomp>= rt   r   c                 s   r   rG   r   r   rE   rE   rF   r     r   r   zdecltype({}))alltargetsr(   rM   r   r   rZ   r   r   r   re   r   r   r   r   r\   Z
iscombinedrU   r   builder
AssignableZAssignableNoEscapeZ	NamedTypeZLazyr   r   )rB   rK   r   r   
alltargetsislocalra   rE   rA   rF   visit_Assign~  s^   

zCxxFunction.visit_Assignc                 C   sH   |  |j}|  |j}tt|j }t|||dd }| ||S )Nrt   )rM   r   targetr*   r   opr   r   )rB   rK   r   r   r   ra   rE   rE   rF   visit_AugAssign  s
   zCxxFunction.visit_AugAssignc                    s@    fdd|j D }td|jrdndd|} ||S )Nc                    r^   rE   r_   r   rA   rE   rF   rY     rb   z+CxxFunction.visit_Print.<locals>.<listcomp>z!pythonic::builtins::print{0}({1})r=   Z_nonlr   )valuesr   rU   nlr   r   )rB   rK   r  ra   rE   rA   rF   visit_Print  s   zCxxFunction.visit_Printc                 C   sf   t | j| D ]'}t|tjs dS t|tD ]}d|jv r-|| j	vr)t
d|  dS qqJ d)NFZcollapsez@not pure expression used as loop target inside a collapse clauseTzunreachable state)reversedZ	ancestorsr   r   r    r6   r   r&   sr   r(   )rB   looprK   Zancestorr   rE   rE   rF   is_in_collapse  s   

	zCxxFunction.is_in_collapsec                 C   s   d t|}| jj|}|jj| jvo#|jj| j| v o#t| d }|r1d}	| j	
|jj nd}	td |	||}
| |||}td |d ||d |t|
|g}| ||gS )	ao  
        Create For representation on iterator for Cxx generation.

        Examples
        --------
        >> "omp parallel for"
        >> for i in range(10):
        >>     ... do things ...

        Becomes

        >> "omp parallel for shared(__iterX)"
        >> for(decltype(__iterX)::iterator __targetX = __iterX.begin();
               __targetX < __iterX.end(); ++__targetX)
        >>         auto&& i = *__targetX;
        >>     ... do things ...

        It the case of not local variable, typing for `i` disappear and typing
        is removed for iterator in case of yields statement in function.
        __target{0}yieldszauto&&r=   z
{} {}= *{}z
{}.begin()z{0} < {1}.end()z++{0})rU   re   r\   r   ZIteratorOfTyper   r   r   hasattrr   remover   make_assignr    r   r   )rB   rK   r   
local_iterlocal_iter_decl	loop_bodyZlocal_targetZlocal_target_declr   Z
local_typeZloop_body_preludeZassignr  rE   rE   rF   gen_for  s,   



zCxxFunction.gen_forc                 C   s   t |dkr	d}n5t|d rddt|d jdk  }n!t|d r<t|d r<ddt|d jt|d jk  }nd}|dkrDdnd}|||}|S )zm
        Handle comparison for real loops.

        Add the correct comparison operator if possible.
           rt   r   r   z{} < {}z{} > {})rZ   r3   intr   rU   )rB   r   r   upper_boundZorder
comparisonrE   rE   rF   handle_real_loop_comparison  s   &z'CxxFunction.handle_real_loop_comparisonc                 C   sj  |j j}t|dkrdn| |d }t|dkrd}d}n	| |d }d}d }}	| || }
| ||| r=|
}ndt|}|jj| jvoY|jj| j	| v oYt
| d }|rht }| j|jj nd	}	td
||td||g}| |||}td|	|||d|||}|d| || ||
u rg }||fS | |||
}t|g}||fS )a)  
        Create C For representation for Cxx generation.

        Examples
        --------
        >> for i in range(10):
        >>     ... do things ...

        Becomes

        >> for(long i = 0, __targetX = 10; i < __targetX; i += 1)
        >>     ... do things ...

        Or

        >> for i in range(10, 0, -1):
        >>     ... do things ...

        Becomes

        >> for(long i = 10, __targetX = 0; i > __targetX; i += -1)
        >>     ... do things ...


        It the case of not local variable, typing for `i` disappear
        r  Z1Lrt   Z0Lr   zlong r  r	  r=   z{} == {}z{} -= {}z{0} {1}={2}z
{0} += {1})iterr   rZ   rM   r  rU   re   r   r   r   r
  r}   r   r  r$   r   r  r    insertr   r  )rB   rK   r  r  r   stepZlower_boundZ	upper_argZ
upper_typeZ	iter_typeZupper_valuer  r   r  r  ZforloopheaderZassgntrE   rE   rF   	gen_c_for  sN   


zCxxFunction.gen_c_forc              	      s  t |tD ]y t fdddD r1  jd7  _ jt|t	 dd  j
 jd  |jttjs<J d jv }d jv}tfd	d jD }|r|r|rj| j| vr  jd
7  _ jtjt	 dd  j jd  qdS )a"  
        Fix OpenMP directives on For loops.

        Add the target as private variable as a new variable may have been
        introduce to handle cxx iterator.

        Also, add the iterator as shared variable as all 'parallel for chunck'
        have to use the same iterator.
        c                 3   s    | ]}| j v V  qd S rG   )r  )rV   rz   )r   rE   rF   r   m      z-CxxFunction.handle_omp_for.<locals>.<genexpr>)z
 parallel z task z shared({})Nr   fordefaultc                 3   s(    | ]}t |tjo|j jkV  qd S rG   )r   r   r   re   )rV   rv   )r   rE   rF   r   y  s    

z private({}))r6   r   r&   anyr  r   r   r   r   Loadr   r   r   r   re   r   r   )rB   rK   r  ZhasforZ	nodefaultZ
noindexrefrE   )r   r   rF   handle_omp_forb  s0   


zCxxFunction.handle_omp_forc                 C   sD   t |jtjo|jj| j| v o|jj| jv}|t|t	 M }|S )aN  
        Check if given for Node can use autoFor syntax.

        To use auto_for:
            - iterator should have local scope
            - yield should not be use
            - OpenMP pragma should not be use

        TODO : Yield should block only if it is use in the for loop, not in the
               whole function.
        )
r   r   r   r   re   r   r   r6   r   r&   )rB   rK   Zauto_forrE   rE   rF   can_use_autofor  s   zCxxFunction.can_use_autoforc                 C   s   t |jtjs	J tjtjtdt dddt dt g d}t }|j	D ]}|
dd | t|D  q(t||j}|j|vsL|jj|v rNdS |jj}t|d	k rZd
S t|d rbd
S dS )z
        Check if a for loop can use classic C syntax.

        To use C syntax:
            - target should not be assign in the loop
            - range should be use as iterator
            - order have to be known at compile time
        builtinsNr   )r   r   r   )funcr   keywordsc                 S   r   rE   r   r   rE   rE   rF   r     r   z,CxxFunction.can_use_c_for.<locals>.<setcomp>F   Tr  )r   r   r   r   ZCallZ	Attributer  r   r~   r   r   r   r   r   searchr  re   r   rZ   r3   )rB   rK   Zpattern_rangeZis_assignedra   Znodesr   rE   rE   rF   can_use_c_for  s&   	
zCxxFunction.can_use_c_forc                 C   s   d |||S )Nz{0} {1} = {2}rT   rB   r  r  iterablerE   rE   rF   r    s   zCxxFunction.make_assignc                    sF  t |jtjstd|j |j}t fdd|jD } |||jj	} |j
} |r= |||\}}nJ |rZg } j|jj	 t|||} ||g}n-dt	|} jj j|j
 }	 ||  |	||}
t|
g} ||||	|}t|tjD ]}|td|j| qt|| S )a  
        Create For representation for Cxx generation.

        Examples
        --------
        >> for i in range(10):
        >>     ... work ...

        Becomes

        >> typename returnable<decltype(builtins.range(10))>::type __iterX
           = builtins.range(10);
        >> ... possible container size reservation ...
        >> for (auto&& i: __iterX)
        >>     ... the work ...

        This function also handle assignment for local variables.

        We can notice that three kind of loop are possible:
        - Normal for loop on iterator
        - Autofor loop.
        - Normal for loop using integer variable iteration
        Kind of loop used depend on OpenMP, yield use and variable scope.
        z7Using something other than an identifier as loop targetc                    r^   rE   r_   r`   rA   rE   rF   rY     rb   z)CxxFunction.visit_For.<locals>.<listcomp>z	__iter{0}z!pythonic::utils::reserve({0},{1}))r   r   r   r   r(   rM   r   r   r   re   r  r'  r  r!  r   r  r%   r   rU   r\   r   r   r   r  r   r  r6   r   ZComprehensionr   )rB   rK   r   r  r)  r  r  Zautoforr  r  ZasgntcomprE   rA   rF   	visit_For  s@   





zCxxFunction.visit_Forc                    s:     |j} fdd|jD }t|t|} ||S )zh
        Create While node for Cxx generation.

        It is a cxx_loop to handle else clause.
        c                    r^   rE   r_   r   rA   rE   rF   rY     rb   z+CxxFunction.visit_While.<locals>.<listcomp>)rM   testr   r!   r   r   )rB   rK   r,  r   ra   rE   rA   rF   visit_While  s   zCxxFunction.visit_Whilec                    sD    fdd|j D }t }|jD ]
}| | qtt||S )Nc                    r^   rE   r_   r   rA   rE   rF   rY     rb   z)CxxFunction.visit_Try.<locals>.<listcomp>)r   r}   handlersextendrM   r"   r   )rB   rK   r   Zexcept_r   rE   rA   rF   	visit_Try  s
   
zCxxFunction.visit_Tryc                    sl   |j r	|j nd fdd|jD  t|jtjr( fdd|jjD S t|jo/|jj	t
 gS )Nc                    r^   rE   r_   )rV   mrA   rE   rF   rY     rb   z3CxxFunction.visit_ExceptHandler.<locals>.<listcomp>c                    s   g | ]}t |jt qS rE   )r#   r   r   )rV   p)r   r   rE   rF   rY     s    )r   rM   r   r   r   r   Tupleeltsr#   r   r   r   rE   )r   r   rB   rF   visit_ExceptHandler  s   zCxxFunction.visit_ExceptHandlerc                    s     |j} fdd|jD } fdd|jD }t|jr*|jjdkr*t|}nt|t||r5t|nd } | 	||S )Nc                    r^   rE   r_   r   rA   rE   rF   rY      rb   z(CxxFunction.visit_If.<locals>.<listcomp>c                    r^   rE   r_   r   rA   rE   rF   rY   !  rb   rt   )
rM   r,  r   rc   r3   r   r   r$   r   r   )rB   rK   r,  r   rc   ra   rE   rA   rF   visit_If  s   

zCxxFunction.visit_Ifc                 C   s$   |j o| |j }td|pdS )Nz	throw {0}r=   )excrM   r   rU   )rB   rK   r7  rE   rE   rF   visit_Raise*  s   zCxxFunction.visit_Raisec                 C   s@   |  |j|jo|  |jg}ddd |D }td|S )Nr   c                 s   s    | ]}|r|V  qd S rG   rE   )rV   Z_frE   rE   rF   r   0  s    z+CxxFunction.visit_Assert.<locals>.<genexpr>zpythonic::pythran_assert({0}))rM   r,  msgr   r   rU   )rB   rK   paramsZsparamsrE   rE   rF   visit_Assert.  s   zCxxFunction.visit_Assertc                 C   r   rG   r   r   rE   rE   rF   visit_Import3  r   zCxxFunction.visit_Importc                 C   s   J d)NFz0should be filtered out by the expand_import passrE   r   rE   rE   rF   visit_ImportFrom6     zCxxFunction.visit_ImportFromc                 C   s$   t | |j}| || ||S rG   )r   rM   r   r   r   rB   rK   ra   rE   rE   rF   
visit_Expr9  s   
zCxxFunction.visit_Exprc                 C   s   t  }| ||S rG   )r   r   r?  rE   rE   rF   
visit_Pass>  s   zCxxFunction.visit_Passc                 C   s>   | j r| j d r| j| j d  td| j d S tdS )zp
        Generate break statement in most case and goto for orelse clause.

        See Also : cxx_loop
        r   goto {0}break)rd   rf   r   r   rU   r   rE   rE   rF   visit_BreakB  s   zCxxFunction.visit_Breakc                 C   s   t dS )Ncontinue)r   r   rE   rE   rF   visit_ContinueN  r>  zCxxFunction.visit_Continuec                    s,    fdd|j D }tt|j }t||S )Nc                    r^   rE   r_   )rV   r   rA   rE   rF   rY   S  rb   z,CxxFunction.visit_BoolOp.<locals>.<listcomp>)r  r)   r   r   r:   )rB   rK   r  r   rE   rA   rF   visit_BoolOpR  s   
zCxxFunction.visit_BoolOpc                 C   sl   |  |j}|  |j}t|rd|jj}t|jr"d|}n
t|jr,d|}tt|j	 ||S )Nz$std::integral_constant<long, {}>{{}}pythonic::types::str({}))
rM   leftrightr5   rU   r   r2   r)   r   r   )rB   rK   rI  rJ  rE   rE   rF   visit_BinOpW  s   


zCxxFunction.visit_BinOpc                 C   s   |  |j}tt|j |S rG   )rM   operandr)   r   r   )rB   rK   rL  rE   rE   rF   visit_UnaryOpd  s   zCxxFunction.visit_UnaryOpc                 C   s2   |  |j}|  |j}|  |j}d|||S )Nz(((bool){0}) ? typename __combined<decltype({1}), decltype({2})>::type({1}) : typename __combined<decltype({1}), decltype({2})>::type({2})))rM   r,  r   rc   rU   )rB   rK   r,  r   rc   rE   rE   rF   visit_IfExph  s   
zCxxFunction.visit_IfExpc                    s   |j sd j| S  fdd|j D } j| }t|dkr1d jj| j|d S d jj| jd|S )	Nz!{}(pythonic::types::empty_list())c                    r^   rE   r_   r   rA   rE   rF   rY   w  rb   z*CxxFunction.visit_List.<locals>.<listcomp>rt   ){0}({1}, pythonic::types::single_value())r   z{0}({{{1}}})r   )	r4  rU   r\   rZ   r   r   rq   r   r   )rB   rK   r4  	node_typerE   rA   rF   
visit_Listr  s   
zCxxFunction.visit_Listc                    s   |j sdj| S fdd|j D }jjj|  t|dkr6djj j|d S d d fd	d
|D S )Nz {}(pythonic::types::empty_set())c                    r^   rE   r_   r   rA   rE   rF   rY     rb   z)CxxFunction.visit_Set.<locals>.<listcomp>rt   rO  r   {0}{{{{{1}}}}}r   c                 3   s    | ]	}d   |V  qdS )zstatic_cast<{}::value_type>({})NrT   rV   elt)rP  rE   rF   r     s    
z(CxxFunction.visit_Set.<locals>.<genexpr>)	r4  rU   r\   r   r   rZ   rq   r   r   )rB   rK   r4  rE   )rP  rB   rF   	visit_Set  s   zCxxFunction.visit_Setc              	      sp   |j sd j| S  fdd|j D } fdd|jD }d jj j| ddd t||D S )	Nz!{}(pythonic::types::empty_dict())c                    r^   rE   r_   r   rA   rE   rF   rY     rb   z*CxxFunction.visit_Dict.<locals>.<listcomp>c                    r^   rE   r_   r   rA   rE   rF   rY     rb   rR  r   c                 s        | ]\}}d  ||V  qdS )z{{ {0}, {1} }}NrT   rV   r   r   rE   rE   rF   r         z)CxxFunction.visit_Dict.<locals>.<genexpr>)keysrU   r\   r  r   r   r   r[   )rB   rK   rY  r  rE   rA   rF   
visit_Dict  s   
zCxxFunction.visit_Dictc                    sV    fdd|j D } j| }dd|}t| jjjr)d| j|S |S )Nc                    r^   rE   r_   rS  rA   rE   rF   rY     rb   z+CxxFunction.visit_Tuple.<locals>.<listcomp>z pythonic::types::make_tuple({0})r   z({}){})	r4  r\   rU   r   r   r   ZCombinedTypesrq   r   )rB   rK   r4  Z
tuple_typer>   rE   rA   rF   visit_Tuple  s   
zCxxFunction.visit_Tuplec                    s^     |j}dd |jD } fdd|jD }t|g|d d  ||}ddd |D S )Nc                 S   s   g | ]}t t| qS rE   )r)   r   r   rE   rE   rF   rY     r   z-CxxFunction.visit_Compare.<locals>.<listcomp>c                    r^   rE   r_   r   rA   rE   rF   rY     rb   r   z and c                 s   s     | ]\}}}|||V  qd S rG   rE   )rV   rv   r   yrE   rE   rF   r     s    z,CxxFunction.visit_Compare.<locals>.<genexpr>)rM   rI  opscomparatorsr[   r   )rB   rK   rI  r]  r^  Zall_cmpsrE   rA   rF   visit_Compare  s
   zCxxFunction.visit_Comparec                    sZ    fdd|j D } |j}|dkr$dd|j d j  |d S d|d	|S )
Nc                    r^   rE   r_   r   rA   rE   rF   rY     rb   z*CxxFunction.visit_Call.<locals>.<listcomp>z&pythonic::builtins::functor::getattr{}z'pythonic::builtins::getattr({}{{}}, {})zpythonic::types::attr::rt   r   z{}({})r   )r   rM   r#  rU   r   upperr   )rB   rK   r   r#  rE   rA   rF   
visit_Call  s   zCxxFunction.visit_Callc                 C   s8  |j d u rd}nut|j trt|j  }ngt|j trB|j dddd}t|j dkr;|dd}d	| d
 }nBd| d }n;t|j trVdt	t |j j
|j j}n't|j r^d}nt|j ro|j dkrjdndd }nt|j tt|j d }|| jv rt|j tsJ dt	t|j  t|j  f S |S )Npythonic::builtins::None"z\"
z\nrt   'z\'zpythonic::types::chr('z')zpythonic::types::str("z")z{0}({1}, {2})zpythonic::numpy::nanr   +-zpythonic::numpy::infr=   z std::integral_constant<%s, %s>{})r   r   boolr   lowerreplacerZ   complexrU   r,   realimagr8   r9   reprr-   r   r   Z
immediatesr  )rB   rK   retZquotedrE   rE   rF   visit_Constant  s6   



zCxxFunction.visit_Constantc                 C   s0   t |\}}dtt|}| s|d7 }|S )Nz::z{})r/   r   mapr1   Z	isliteral)rB   rK   objpathZsattrrE   rE   rF   visit_Attribute  s
   zCxxFunction.visit_Attributec                    s4   t |tjrt fdd|jD S  j| jdkS )Nc                 3   s     | ]} j | jd kV  qdS )r   N)range_valueslowrS  rA   rE   rF   r     s    z+CxxFunction.all_positive.<locals>.<genexpr>r   )r   r   r3  r   r4  ru  rv  r   rE   rA   rF   all_positive  s
   zCxxFunction.all_positivec                    s     |j}t|jrd|}t|jr*|jjdkr*t|jjtr*d|jj|S  |jr<  |j}d||S t	|jrU fdd|jj
D }dd||S   |j}d	||S )
NrH  r   zstd::get<{0}>({1})z{1}.fast({0})c                    r^   rE   r_   rS  rA   rE   rF   rY     rb   z/CxxFunction.visit_Subscript.<locals>.<listcomp>z{1}({0}),z{1}[{0}])rM   r   r2   rU   r3   slicer   r  rw  r4   r4  r   )rB   rK   r   Zslice_ZslicesrE   rA   rF   visit_Subscript  s"   




zCxxFunction.visit_Subscriptc                 C   s<   |j | jv rt|j S |j | jv rdt|j S t|j S )Nz{0}())re   r   r1   Zglobal_declarationsrU   r   rE   rE   rF   
visit_Name  s
   

zCxxFunction.visit_Namec                 C   s   g }dD ]}t ||}|r| |nd}|| q|jd u s*t|jrE|jjdkrE| |jr9| |jr9d}nd}|	|d |d S dj	| S )N)ri  r`  r  rb  rt   z-pythonic::types::fast_contiguous_slice({},{})z(pythonic::types::contiguous_slice({},{})r   z pythonic::types::slice({},{},{}))
r   rM   r   r  r3   r   rw  ri  r`  rU   )rB   rK   r   ZfieldZnfieldr   r   rE   rE   rF   visit_Slice  s   
 
zCxxFunction.visit_SlicerG   ):rN   rO   rP   rQ   r@   r   r   r   rM   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r   r!  r'  r  ri   r+  r-  r0  r5  r6  r8  r;  r<  r=  r@  rA  rD  rF  rG  rK  rM  rN  rQ  rU  rZ  r[  r_  ra  rp  rt  rw  rz  r{  r|  rR   rE   rE   rC   rF   r      sp    
E51K"
H

	
r   c                       sd   e Zd ZdZdZdZdd Z fddZdd	 Zd
d Z	dd Z
dd Zdd Z fddZ  ZS )r   Z__generator_stateZ__generator_valueZthat_is_all_folksc                 G   s   |S rG   rE   )rB   rK   r   r   rE   rE   rF   r   #  s   zCxxGenerator.process_localsc                    s2   g | _ dd t| t|D | _tt| |S )Nc                 S   s(   i | ]\}}|d | d d | fqS )rt   zyield_point{0}rT   )rV   r   r   rE   rE   rF   r   *  s   ( z<CxxGenerator.prepare_functiondef_context.<locals>.<dictcomp>)extra_declarationsr   r   r   r	  r?   r   r   r   rC   rE   rF   r   &  s
   z(CxxGenerator.prepare_functiondef_contextc                    s  d_ |}|\}}}|}|\}}}}	}
dt|j}d||r.dd|nd}j r<|tt	j
 |td ttdd	g t g}tttd|g td
g}|r|rgt|rgt }|tt|d||||tdddgdd |D   tttddg ttdgtttd|dg dttt	jgtttd|dg ttdtd|gtttd|dg ttd|gg}tttd|d|g |}|}|dtdt	jddd tj d d! d"D  tj d#d t||D  fd$dj D  d%d j!D  td&|t	jg } fd'dj"| d( D }t#td|rTd)|d|n|d*t#t|$ d+g}t#t|$ dg} % | | | }tt&||| | | | d,|}t|t|}tt'||d-|||||t g}t'||d.t|j||}tt||ttd/|d|g}tt&d0||}t&t|j||	|
g| }||g||gfS )1NFz__generator__{0}r   r   r   r=   zreturn result_type()r   nextz: pythonic::yielder() {}z: {0} {{ }}zpythonic::yielder()c                 S   s   g | ]}d  |qS )z{0}({0})rT   r   rE   rE   rF   rY   V  s    z2CxxGenerator.visit_FunctionDef.<locals>.<listcomp>r   z
operator++znext()ztypename {0}::result_typez	operator*r   z(pythonic::types::generator_iterator<{0}>Zbeginz/pythonic::types::generator_iterator<{0}>(*this)endz*pythonic::types::generator_iterator<{0}>()z	{0}::nextr   zswitch({0}) {{ {1} }} c                 s   rV  )zcase {0}: goto {1};NrT   )rV   numwhererE   rE   rF   r     rX  z1CxxGenerator.visit_FunctionDef.<locals>.<genexpr>c                 S   rs   )Nr   rE   ru   rE   rE   rF   rw     rx   z0CxxGenerator.visit_FunctionDef.<locals>.<lambda>ry   c                 S   s    g | ]\}}t d ||qS r   r   rU   )rV   ZftfarE   rE   rF   rY         c                    s.   g | ]}t d jj|   |qS r   )r   rU   r\   r   rq   r   r   rE   rF   rY     s    
c                 S   s    g | ]\}}t d ||qS r   r  rW  rE   rE   rF   rY     r  ztypename {0}::result_type {1}c                    r   rE   r   r   r   rE   rF   rY     r   rt   z{0}<{1}>iteratorZ
value_typezpythonic::yielderr   r   z{0}({1})r   )(returnsr   r   rU   r1   r   r   r   r   r   FinalStatementr   r   r   r   r   r   r   r}   r   r   r   
StateValuer]   r  StateHolderr{   r	  r  rj   r   r[   r   r}  r\   r   rq   r   r   r   )rB   rK   r   r   r   r   r   r   r   r   r   Z	next_nameZinstanciated_next_nameZnext_declarationZnext_constructorsZnext_iteratorZnext_signatureZ	next_bodyZnext_membersZextern_typedefsZiterator_typedefZresult_typedefr   Znext_structZnext_definitionr   r   r   Ztopstruct_typer   rE   r   rF   r   /  s  



	
!	


		zCxxGenerator.visit_FunctionDefc                 C   s*   d| _ ttdtjtdtjgS )NTz{0} = -1rB  )r  r   r   rU   r   r  r  r   rE   rE   rF   r     s   zCxxGenerator.visit_Returnc                 C   sX   | j | \}}ddd tttj|tdtj| 	|j
td|g D S )Nr=   c                 s   s    | ]}|V  qd S rG   rE   r   rE   rE   rF   r     s    z+CxxGenerator.visit_Yield.<locals>.<genexpr>z	{0} = {1}z{0}:)r	  r   r   r   r   r  r   rU   r  rM   r   r   rq   )rB   rK   r  ZlabelrE   rE   rF   visit_Yield  s   


zCxxGenerator.visit_Yieldc                    s@     |j} fdd|jD }d|}t||} ||S )Nc                    r^   rE   r_   r   rA   rE   rF   rY     rb   z-CxxGenerator.visit_Assign.<locals>.<listcomp>r   )rM   r   r   r   r   r   )rB   rK   r   r   r   ra   rE   rA   rF   r     s
   

zCxxGenerator.visit_Assignc                 C   s   dS )zx
        TODO : Yield should block only if it is use in the for loop, not in the
               whole function.
        FrE   r   rE   rE   rF   r!    s   zCxxGenerator.can_use_autoforc                    s$   | j ||f tt| d||S r<   )r}  r   r?   r   r  r(  rC   rE   rF   r    s   zCxxGenerator.make_assign)rN   rO   rP   r  r  r  r   r   r   r   r  r   r!  r  rR   rE   rE   rC   rF   r     s    	 &	r   c                       s0   e Zd ZdZ fddZdd Zdd Z  ZS )Cxxah  
    Produces a C++ representation of the AST.

    >>> import gast as ast, pythran.passmanager as passmanager, os
    >>> node = ast.parse("def foo(): return 'hello world'")
    >>> pm = passmanager.PassManager('test')
    >>> r = pm.dump(Cxx, node)
    >>> print(str(r).replace(os.sep, '/'))
    #include <pythonic/include/types/str.hpp>
    #include <pythonic/types/str.hpp>
    namespace __pythran_test
    {
      struct foo
      {
        typedef void callable;
        typedef void pure;
        struct type
        {
          typedef typename pythonic::returnable<pythonic::types::str>::type result_type;
        }  ;
        inline
        typename type::result_type operator()() const;
        ;
      }  ;
      inline
      typename foo::type::result_type foo::operator()() const
      {
        return pythonic::types::str("hello world");
      }
    }
    c              
      s(   d| _ tt| tttttt	t
t dS r   )r>   r?   r  r@   r   r   r.   r   r	   r
   r   r   rA   rC   rE   rF   r@     s
   zCxx.__init__c           	         s   t  j}dd |D }|dd |D 7 }ttd fdd|jD }|r*t| ng g f\}}dd || D }tt jj	 |}t
||g  _dS )z Build a compilation unit. c                 S   s0   g | ]}t tjjd dgtt|R  d qS )pythonicZinclude.hppr   osrs  r   rq  r1   r   rE   rE   rF   rY   &  s    
z$Cxx.visit_Module.<locals>.<listcomp>c                 S   s.   g | ]}t tjjd gtt|R  d qS )r  r  r  r   rE   rE   rF   rY   )  s    &Nc                 3   s    | ]}  |V  qd S rG   r_   r`   rA   rE   rF   r   ,  r  z#Cxx.visit_Module.<locals>.<genexpr>c                 S   s   g | ]	}|D ]}|qqS rE   rE   )rV   Zlsr  rE   rE   rF   rY   0  s    )r{   Zdependenciesr}   filterr   r[   r   r+   ZpassmanagerZmodule_namer   r>   )	rB   rK   Zheader_depsZheadersZdecls_n_defnsZdeclsZdefnsZnsbodynsrE   rA   rF   visit_Module"  s   

zCxx.visit_Modulec                 C   s&   |  t|}|r
tnt| }||S rG   )r   r   r   r   rM   )rB   rK   r	  ZvisitorrE   rE   rF   r   4  s   
zCxx.visit_FunctionDef)rN   rO   rP   rQ   r@   r  r   rR   rE   rE   rC   rF   r    s
    !r  rG   )NN)UrQ   Zpythran.analysesr   r   r   r   r   r   r   r	   r
   r   r   r   Zpythran.cxxgenr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   Zpythran.openmpr&   Zpythran.passmanagerr'   Zpythran.syntaxr(   Zpythran.tablesr)   r*   r+   Zpythran.types.conversionr,   r-   Zpythran.types.typesr.   Zpythran.utilsr/   r0   r1   r2   r3   r4   r5   Zpythranr6   r7   Zmathr8   r9   Zgastr   r  	functoolsr:   rH   r;   r]   ri   rj   r   r   r   ZNodeVisitorr   r   r  rE   rE   rE   rF   <module>   sX     
0%

      j ^