o
    @az"                     @   s   d Z ddlmZmZ ddlmZ ddlmZ ddlm	Z	m
Z
mZmZ ddlmZ ddlmZ ddlmZmZ dd	lZdd
lmZ dd	lZedZG dd deZG dd deZd	S )z< ConstantFolding performs some kind of partial evaluation.      )ConstantExpressions
ASTMatcher)Transformation)MODULES)to_astConversionError	ToNotEvalmangle)DamnTooLongPattern)PythranSyntaxError)
isintegralisnumN)deepcopyZpythranc                       sT   e Zd ZdZdd Z fddZdd Ze ZZe	j
 ZZe	j
 ZZdd	 Z
  ZS )
ConstantFoldingae  
    Replace constant expression by their evaluation.

    >>> import gast as ast
    >>> from pythran import passmanager, backend
    >>> node = ast.parse("def foo(): return 1+3")
    >>> pm = passmanager.PassManager("test")
    >>> _, node = pm.apply(ConstantFolding, node)
    >>> print(pm.dump(backend.Python, node))
    def foo():
        return 4
    c                 C      t | t d S Nr   __init__r   self r   H/usr/lib/python3/dist-packages/pythran/optimizations/constant_folding.pyr   !      zConstantFolding.__init__c              	      s   t |tjsJ dtdi| _tD ]}|dkr.t|}z	t|| j|< W q ty-   Y qw qtdd |jD g }t	t
t|dd| j tt| | d S )Nbuiltins__dispatch__c                 S   s   g | ]
}t |tjs|qS r   )
isinstanceastZImport).0sr   r   r   
<listcomp>6   s    

z+ConstantFolding.prepare.<locals>.<listcomp>z<constant_folding>exec)r   r   ZModule
__import__envr   r	   ImportErrorbodyevalcompilegast_to_astsuperr   prepare)r   nodeZmodule_nameZalias_module_nameZdummy_module	__class__r   r   r)   $   s*   
zConstantFolding.preparec                 C   s   |S r   r   r   r*   r   r   r   skip?   s   zConstantFolding.skipc              
   C   s  t |tjr|| jv rt|}tt|dd}z:t|| j}t	|}zt
||s3d| _|W W S W n tyL } ztd|d W Y d }~nd }~ww t| |W S  tye } ztd|  d }~w tys   t| | Y S  ty } ztd|jd   t| |W  Y d }~S d }~w ty } z)d	|jd v rt| |W  Y d }~S td|jd   t| |W  Y d }~S d }~w ty } ztt||d }~ww t| |S )
Nz<constant folding>r%   TzW: z Assume no update happened.zerror in constant folding: z-During constant folding, bailing out due to: r   r   )r   r   exprconstant_expressionsZ
Expressionr&   r'   r%   r"   r   r   searchupdater
   printr   generic_visitr   r   AttributeErrorloggerinfoargs	NameError	Exceptionr   str)r   r*   Z	fake_nodecodevalueZnew_nodeer   r   r   r4   G   sV   


zConstantFolding.generic_visit)__name__
__module____qualname____doc__r   r)   r.   Zvisit_ConstantZ
visit_Namer   r4   Z
visit_ListZ	visit_SetZ
visit_DictZvisit_Tuple__classcell__r   r   r+   r   r      s    

r   c                   @   s@   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dS )PartialConstantFoldinga  
    Replace partially constant expression by their evaluation.

    >>> import gast as ast
    >>> from pythran import passmanager, backend

    >>> node = ast.parse("def foo(n): return [n] * 2")
    >>> pm = passmanager.PassManager("test")
    >>> _, node = pm.apply(PartialConstantFolding, node)
    >>> print(pm.dump(backend.Python, node))
    def foo(n):
        return [n, n]

    >>> node = ast.parse("def foo(n): return 2 * (n,)")
    >>> _, node = pm.apply(PartialConstantFolding, node)
    >>> print(pm.dump(backend.Python, node))
    def foo(n):
        return (n, n)

    >>> node = ast.parse("def foo(n): return [n] + [n]")
    >>> _, node = pm.apply(PartialConstantFolding, node)
    >>> print(pm.dump(backend.Python, node))
    def foo(n):
        return [n, n]

    >>> node = ast.parse("def foo(n, m): return (n,) + (m, n)")
    >>> _, node = pm.apply(PartialConstantFolding, node)
    >>> print(pm.dump(backend.Python, node))
    def foo(n, m):
        return (n, m, n)
    c                 C   r   r   r   r   r   r   r   r      r   zPartialConstantFolding.__init__c                 C   H   t |jtjtjfsdS t|jsdS t|jstd|t |j	tj
S NFz!Multiplying a sequence by a float)r   leftr   ListTupler   rightr   r   opMultr-   r   r   r   fold_mult_left      


z%PartialConstantFolding.fold_mult_leftc                 C   rE   rF   )r   rJ   r   rH   rI   r   rG   r   r   rK   rL   r-   r   r   r   fold_mult_right   rN   z&PartialConstantFolding.fold_mult_rightc                 C   s.   t |j|sdS t |j|sdS t |jtjS )NF)r   rG   rJ   rK   r   Addr   r*   Ztyr   r   r   fold_add   s
   zPartialConstantFolding.fold_addc                    s    | j v r S |   |  r&d| _ fddt jjD  j_ jS | 	 r<d| _ j j _ _| 
 S tjtjfD ]}|  |r\d| _ j j jj7  _ j  S qB S )NTc                    s"   g | ]} j jD ]}t|qqS r   )rG   eltsr   )r   _eltr*   r   r   r      s    z6PartialConstantFolding.visit_BinOp.<locals>.<listcomp>)r0   r4   rM   r2   rangerJ   r=   rG   rS   rO   Zvisitr   rH   rI   rR   rQ   r   rV   r   visit_BinOp   s(   








z"PartialConstantFolding.visit_BinOpc              	   C   s   |  | t|jtjs|S t|jjtjs|S t|js|S |jj}|j}|j}|jp1t	dd}|j
p:t	dd}t|t t|t ||_d| _|S )a  
        >>> import gast as ast
        >>> from pythran import passmanager, backend
        >>> pm = passmanager.PassManager("test")

        >>> node = ast.parse("def foo(a): a[1:][3]")
        >>> _, node = pm.apply(PartialConstantFolding, node)
        >>> _, node = pm.apply(ConstantFolding, node)
        >>> print(pm.dump(backend.Python, node))
        def foo(a):
            a[4]

        >>> node = ast.parse("def foo(a): a[::2][3]")
        >>> _, node = pm.apply(PartialConstantFolding, node)
        >>> _, node = pm.apply(ConstantFolding, node)
        >>> print(pm.dump(backend.Python, node))
        def foo(a):
            a[6]

        >>> node = ast.parse("def foo(a): a[-4:][5]")
        >>> _, node = pm.apply(PartialConstantFolding, node)
        >>> _, node = pm.apply(ConstantFolding, node)
        >>> print(pm.dump(backend.Python, node))
        def foo(a):
            a[1]
        r   N   T)r4   r   r=   r   Z	SubscriptsliceZSlicer   lowerZConstantstepZBinOprP   rL   r2   )r   r*   Zslice_indexr[   r\   r   r   r   visit_Subscript   s*   

z&PartialConstantFolding.visit_SubscriptN)
r?   r@   rA   rB   r   rM   rO   rR   rX   r^   r   r   r   r   rD   o   s     

rD   )rB   Zpythran.analysesr   r   Zpythran.passmanagerr   Zpythran.tablesr   Zpythran.conversionr   r   r   r	   Zpythran.analyses.ast_matcherr
   Zpythran.syntaxr   Zpythran.utilsr   r   Zgastr   copyr   ZloggingZ	getLoggerr6   r   rD   r   r   r   r   <module>   s    
]