o
    "jc8                     @   s   d dl m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 g ZdZdZG d	d
 d
e
ZG dd deZdd ZG dd deZdS )    )unique_name)BaseNodeVisitorindex_in_list)create_bool_node)gast   )BaseTransformerForNodeVisitorZ__breakZ
__continuec                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	ForToWhileTransformerz_
    Transform python for loop into while loop and add condition node in the
    loop test
    c                 C   s*   t |tjs
J d|| _|| _|| _d S )Nz2loop_node is not gast.For in ForToWhileTransformer)
isinstancer   Forparent_node	loop_nodecondition_node)selfr   r   r    r   p/var/www/html/Deteccion_Ine/venv/lib/python3.10/site-packages/paddle/jit/dy2static/break_continue_transformer.py__init__"   s   
zForToWhileTransformer.__init__c                 C   s   t | jdr+| jj}t|| j}|dkr+| || }||||d < |t|7 }|S t | jdrV| jj}t|| j}|dkrV| || }||||d < |t|7 }|S td)Nbodyr   orelsezBparent_node doesn't contain the loop_node in ForToWhileTransformer)	hasattrr   r   r   r   get_for_stmt_nodeslenr   
ValueError)r   Z	body_listiZ	new_stmtsr   r   r   	transform*   s&   zForToWhileTransformer.transformc           	      C   st   t |tjs
J dt|}| }|d u r|gS |\}}}tjt || jgd}tj|||j	d}|
| |S )Nz0Input node is NOT gast.For in get_for_stmt_nodesopvaluestestr   r   )r   r   r   r	   parseBoolOpAndr   Whiler   append)	r   nodeZcurrent_for_node_parserZstmts_tupleZ
init_stmtsZ	cond_stmtZ
body_stmtsZnew_cond_stmtZ
while_noder   r   r   r   ?   s$   

z(ForToWhileTransformer.get_for_stmt_nodesN)__name__
__module____qualname____doc__r   r   r   r   r   r   r   r
      s
    r
   c                       sh   e Zd Zd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  ZS )BreakContinueTransformera  
    Rewrite 'break' and 'continue' key words in a if-else python way to make
    it equivalent to original control flow

    The main idea of this class is:

        1. Map the 'break/continue' stmt with an unique boolean variable V.

        2. Find the first ancestor block containing this 'break/continue', a
        block can be a node containing stmt list. We should remove all stmts
        after the 'break/continue' and set the V to True here.

        3. Add 'if V' for stmts in ancestor blocks between the first one
        (exclusive) and the ancestor loop (inclusive)

        4. For 'break' add break into condition of the loop. For 'continue',
        set continue to False at the beginning of each loop

        TODO: more details should be summarized as design document

    Note: The class is inherited from BaseNodeVisitor instead of NodeTransformer,
          because ancestor nodes will be modified inplace for `Break/Continue` here.
          In general, we recommend to inheriting NodeTransformer to modify node!
    c                       t    || _d S Nsuperr   rootr   r1   	__class__r   r   r   r      

z!BreakContinueTransformer.__init__c                 C      |  | j d S r.   visitr1   r   r   r   r   r   w      z"BreakContinueTransformer.transformc           
      C   s   t || j}|dksJ d| j| }tt}| |||}| ||| t|d}| || t	j
t	 t	j|t	 d d dd}t|t	jrXt	jt	 |j|gd|_d S t|t	jrq| j|d  }t|||}	|	  d S d S )Nr   !SyntaxError: 'break' outside loopFidctx
annotationtype_commentr   operandr   r   )_find_ancestor_loop_indexancestor_nodesr   generateBREAK_NAME_PREFIX"_remove_stmts_after_break_continue_replace_if_stmtr   _add_stmt_before_cur_noder   UnaryOpNotNameLoadr   r%   r#   r$   r!   r   r
   r   )
r   r'   loop_node_indexr   variable_namefirst_block_indexassign_false_nodecond_var_noder   for_to_whiler   r   r   visit_Breakz   s<   



z$BreakContinueTransformer.visit_Breakc                 C   sh   t || j}|dksJ d| j| }tt}| |||}| ||| t|d}|j	d| d S )Nr   z$SyntaxError: 'continue' outside loopFr   )
rC   rD   r   rE   CONTINUE_NAME_PREFIXrG   rH   r   r   insert)r   r'   rN   r   rO   rP   rQ   r   r   r   visit_Continue   s   


z'BreakContinueTransformer.visit_Continuec                 C   sr   t t| jd |d dD ])}| j| }t|dr%| |j||r%|  S t|dr6| |j||r6|  S q|S Nr   r   r   r   )ranger   rD   r   $_replace_break_continue_in_stmt_listr   r   )r   break_continue_nodebreak_continue_namerN   rP   Zfirst_blockr   r   r   rG      s,   
z;BreakContinueTransformer._remove_stmts_after_break_continuec                 C   sn   t |d |d dD ]*}| j| }| j|d  }t|dr&| |j||r&q
t|dr4| |j||r4q
q
d S rX   )rY   rD   r   &_replace_after_node_to_if_in_stmt_listr   r   )r   rN   rP   r\   r   cur_nodeZson_noder   r   r   rH      s*   
z)BreakContinueTransformer._replace_if_stmtc                 C   s2   t ||}|dkrdS t|d}|g||d < dS Nr   FT)r   r   )r   	stmt_listr[   r\   r   Zassign_true_noder   r   r   rZ      s   

z=BreakContinueTransformer._replace_break_continue_in_stmt_listc              	   C   s   t ||}|dkrdS |t|d krdS tjtjt tj|t d d dd||d d  g d}g ||d d < || dS )Nr   Fr   Tr<   rA   r    )	r   r   r   IfrJ   rK   rL   Storer&   )r   r`   r'   r\   r   Zif_stmtr   r   r   r]      s*   
	
z?BreakContinueTransformer._replace_after_node_to_if_in_stmt_listc                 C   sX   | j | }| j |d  }t|dr| |j||rdS t|dr*| |j||r*dS dS )Nr   r   Tr   F)rD   r   _add_stmt_into_list_before_noder   r   )r   Zcur_node_index	stmt_noder^   r   r   r   r   rI     s&   
z2BreakContinueTransformer._add_stmt_before_cur_nodec                 C   s&   t ||}|dkrdS ||| dS r_   )r   rV   )r   r`   r'   rd   r   r   r   r   rc     s
   
z8BreakContinueTransformer._add_stmt_into_list_before_node)r(   r)   r*   r+   r   r   rT   rW   rG   rH   rZ   r]   rI   rc   __classcell__r   r   r3   r   r,   X   s    ,
r,   c                 C   s<   t t|d ddD ]}t|| tjtjfr|  S q
dS )Nr   r   )rY   r   r   r   r   r%   )r'   rD   r   r   r   r   rC   &  s
   rC   c                       s@   e Zd ZdZ fddZdd Zdd Zdd	 Zd
d Z  Z	S )BreakTransformOptimizera  
    In specific pattern, the transformed code could be optimized by joining the
    If.test with while.test.

    Currently supported pattern is:
    ```
        while cond1:            while cond1 and not cond2:
            if cond2:    --->       do_something()
                break
            do_something()
    ```

    See following example:

    >>> def foo(x):
    ...     i = paddle.to_tensor(1, dtype='int32')
    ...     while i < 10:
    ...         if x.mean() > 5:
    ...             break
    ...         x += i
    ...         i += 1
    ...     return x

    The generated code after applying optimization will be:
    ```
        def foo(x):
            i = paddle.to_tensor(1, dtype='int32')
            while i < 10 and not x.mean() > 5:
                x += i
                i += 1
            return x
    ```
    It can avoid wrapping all ops after `break` statement into `cond_op` that
    usually brings very heavy overhead.
    c                    r-   r.   r/   r2   r3   r   r   r   R  r5   z BreakTransformOptimizer.__init__c                 C   r6   r.   r7   r9   r   r   r   r   W  r:   z!BreakTransformOptimizer.transformc                 C   s   t || j}|dksJ d| j| }| ||rM| ||}t|tjr4tjt |j	|gd|_	d S t|tj
rO| j|d  }t|||}|  d S d S d S )Nr   r;   r   r   )rC   rD   _is_break_cond_pattern_join_with_while_condr   r   r%   r#   r$   r!   r   r
   r   )r   r'   rN   r   rR   r   rS   r   r   r   rT   Z  s"   
z#BreakTransformOptimizer.visit_Breakc                 C   s   t | jdk s| jd |krdS | jd |ksJ | jd }d}t|tjr?|jd |ko3t |jdk}|jd |k}|o>|}|S )zX
        Judge whether if match the pattern to join `If.test` with `while.test`
           Fr   r   )r   rD   r   r   ra   r   r   )r   
break_noder   parent_if_nodeZ
is_matchedZbreak_first_in_ifZif_first_in_loopr   r   r   rg   m  s   
z.BreakTransformOptimizer._is_break_cond_patternc                 C   s@   | j d }tjt |jd}|jd |ksJ |jd |S )z@
        Join the `If.test` with `While.test` together.
        rk   rA   r   )rD   r   rJ   rK   r!   r   pop)r   rl   r   rm   rR   r   r   r   rh     s
   
z-BreakTransformOptimizer._join_with_while_cond)
r(   r)   r*   r+   r   r   rT   rg   rh   re   r   r   r3   r   rf   -  s    $rf   N)Zpaddle.baser   Zpaddle.jit.dy2static.utilsr   r   Z(paddle.jit.dy2static.variable_trans_funcr   Zpaddle.utilsr   Zbase_transformerr   r	   __all__rF   rU   r
   r,   rC   rf   r   r   r   r   <module>   s   < O