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m	Z	 ddl
mZ ddlmZ ddlmZ ddlZzddlmZ W n eyM   ddlmZmZ d	d
 ZY nw G dd dejZG dd deZdS )z`
Replace variable that can be lazy evaluated and used only once by their full
computation code.
    )LazynessAnalysisUseDefChainsDefUseChains)Literals	AncestorsIdentifiersCFG
IsAssigned)TransformationN)defaultdict)isfiniteisinfisnanc                 C   s   t |  o	t|  S Nr   )x r   L/usr/lib/python3/dist-packages/pythran/optimizations/forward_substitution.pyr      s   r   c                   @   s   e Zd Zdd Zdd ZdS )Removerc                 C   s
   || _ d S r   )nodes)selfr   r   r   r   __init__   s   
zRemover.__init__c                    s@   || j v r| j |   fdd|jD |_|jr|S t S |S )Nc                    s   g | ]}| vr|qS r   r   ).0ZtgtZto_pruner   r   
<listcomp>   s    z(Remover.visit_Assign.<locals>.<listcomp>)r   targetsastZPassr   noder   r   r   visit_Assign   s   

zRemover.visit_AssignN)__name__
__module____qualname__r   r   r   r   r   r   r      s    r   c                       s0   e Zd ZdZ fddZdd Zdd Z  ZS )ForwardSubstitutiona{  
    Replace variable that can be computed later.

    >>> import gast as ast
    >>> from pythran import passmanager, backend
    >>> pm = passmanager.PassManager("test")

    >>> node = ast.parse("def foo(): a = [2, 3]; builtins.print(a)")
    >>> _, node = pm.apply(ForwardSubstitution, node)
    >>> print(pm.dump(backend.Python, node))
    def foo():
        pass
        builtins.print([2, 3])

    >>> node = ast.parse("def foo(): a = 2; builtins.print(a + a)")
    >>> _, node = pm.apply(ForwardSubstitution, node)
    >>> print(pm.dump(backend.Python, node))
    def foo():
        a = 2
        builtins.print((2 + 2))

    >>> node = ast.parse("def foo():\n a=b=2\n while a: a -= 1\n return b")
    >>> _, node = pm.apply(ForwardSubstitution, node)
    >>> print(pm.dump(backend.Python, node))
    def foo():
        a = 2
        while a:
            a -= 1
        return 2
    c                    s$   t t| tttttt d| _	dS )z* Satisfy dependencies on others analyses. N)
superr#   r   r   r   r   r   r   r   	to_remove)r   	__class__r   r   r   H   s   
zForwardSubstitution.__init__c                 C   s6   t t| _| jj| | _| | t| j| |S r   )r   listr%   Zdef_use_chainslocalsZgeneric_visitr   Zvisitr   r   r   r   visit_FunctionDefR   s
   

z%ForwardSubstitution.visit_FunctionDefc                    s  t |jtjs	|S || jvr'	 ddlm  t fdd| j| D s%J |S | j| }t	|dkr4|S |d }|j
t tjsC|S tfdd| jD dkrS|S | jv o_t| jj }|| jj dkO }|sn|S | j d }t |tjr|j}| jv rd| _t	| dkr| j|  |S |S t	|jdkr| t|}ttd	d
 | j| D }t| j||}	|	D ]}
|
dd D ]}dd | t |D }|!|s  |S qqd| _| j|  |S |S )NTr   OMPDirectivec                 3   s    | ]}t | V  qd S r   )
isinstance)r   pr+   r   r   	<genexpr>d   s    z1ForwardSubstitution.visit_Name.<locals>.<genexpr>   c                 3   s"    | ]}|   jkrd V  qdS )r0   N)nameid)r   d)dnoder   r   r/   s   s     c                 S   s   g | ]
}t |tjr|qS r   )r-   r   stmt)r   sr   r   r   r      s    

z2ForwardSubstitution.visit_Name.<locals>.<listcomp>c                 S   s   h | ]}|j qS r   )r2   )r   nr   r   r   	<setcomp>   s    
z1ForwardSubstitution.visit_Name.<locals>.<setcomp>)"r-   ctxr   ZLoadZuse_def_chainsZpythran.openmpr,   anyZ	ancestorslenr   Namesumr)   literalsr   Zlazyness_analysisr2   ZAssignvalueupdateZusersr%   appendr   Zgatherr   nextreversedgraphZall_simple_pathsZcfgr	   
isdisjoint)r   r   ZdefusesZdefuseZfwdparentr@   ZidsZ	node_stmtZ	all_pathspathr6   Zassigned_idsr   )r,   r4   r   
visit_Name\   sh   





zForwardSubstitution.visit_Name)r    r!   r"   __doc__r   r*   rI   __classcell__r   r   r&   r   r#   '   s
    

r#   )rJ   Zpythran.analysesr   r   r   r   r   r   r   r	   Zpythran.passmanagerr
   Zpythran.graphrE   collectionsr   Zgastr   Zmathr   ImportErrorr   r   ZNodeTransformerr   r#   r   r   r   r   <module>   s    