U
    nufI                     @   sL  d dl Z d dlZd dlZd dlZd dlZd dlmZ d dlmZmZm	Z	m
Z
mZmZmZmZ d dlZd dlmZ ddlmZ ddlmZmZmZmZmZmZmZmZmZ erddlmZmZ G d	d
 d
e e j!e"Z#G dd de#e"Z$G dd de#e"Z%dZ&ej'dd dkr>e&d7 Z&ej'dd dkr>e&d7 Z&e&d7 Z&dddZ(dS )    N)Module)IterableIteratorListOptionalTupleAnycastTYPE_CHECKING)xrange   )LineNumbers)	Tokenmatch_tokenis_non_coding_tokenpatched_generate_tokens	last_stmtannotate_fstring_nodesgenerate_tokens	is_moduleis_stmt)AstNode	TokenInfoc                   @   s6   e Zd Zdd Zejdd ZdddZddd	Zd
S )ASTTextBasec                 C   s$   || _ t|}|| _t|| _d S N)	_filenamesixensure_text_textr   _line_numbers)selfsource_textfilename r#   7/tmp/pip-unpacked-wheel-0ukdbujv/asttokens/asttokens.py__init__%   s    
zASTTextBase.__init__c                 C   s   t dS )  
    Returns two ``(lineno, col_offset)`` tuples for the start and end of the given node.
    If the positions can't be determined, or the nodes don't correspond to any particular text,
    returns ``(1, 0)`` for both.

    ``padded`` corresponds to the ``padded`` argument to ``ast.get_source_segment()``.
    This means that if ``padded`` is True, the start position will be adjusted to include
    leading whitespace if ``node`` is a multiline statement.
    N)NotImplementedErrorr    nodepaddedr#   r#   r$   get_text_positions4   s    zASTTextBase.get_text_positionsTc                 C   s(   |  ||\}}| jj| | jj| fS )a  
    Returns the (startpos, endpos) positions in source text corresponding to the given node.
    Returns (0, 0) for nodes (like `Load`) that don't correspond to any particular text.

    See ``get_text_positions()`` for details on the ``padded`` argument.
    )r+   r   line_to_offsetr    r)   r*   startendr#   r#   r$   get_text_rangeB   s    

zASTTextBase.get_text_rangec                 C   s   |  ||\}}| j|| S )z
    Returns the text corresponding to the given node.
    Returns '' for nodes (like `Load`) that don't correspond to any particular text.

    See ``get_text_positions()`` for details on the ``padded`` argument.
    )r0   r   r-   r#   r#   r$   get_textP   s    zASTTextBase.get_textN)T)T)	__name__
__module____qualname__r%   abcabstractmethodr+   r0   r1   r#   r#   r#   r$   r   $   s
   

r   c                       s   e Zd ZdZd% fdd	Zdd Zd	d
 Zedd Zedd Z	edd Z
edd Zdd Zdd Zdd Zd&ddZd'ddZd(ddZd)dd Zd*d!d"Zd#d$ Z  ZS )+	ASTTokensa  
  ASTTokens maintains the text of Python code in several forms: as a string, as line numbers, and
  as tokens, and is used to mark and access token and position information.

  ``source_text`` must be a unicode or UTF8-encoded string. If you pass in UTF8 bytes, remember
  that all offsets you'll get are to the unicode text, which is available as the ``.text``
  property.

  If ``parse`` is set, the ``source_text`` will be parsed with ``ast.parse()``, and the resulting
  tree marked with token info and made available as the ``.tree`` property.

  If ``tree`` is given, it will be marked and made available as the ``.tree`` property. In
  addition to the trees produced by the ``ast`` module, ASTTokens will also mark trees produced
  using ``astroid`` library <https://www.astroid.org>.

  If only ``source_text`` is given, you may use ``.mark_tokens(tree)`` to mark the nodes of an AST
  tree created separately.
  FN	<unknown>c                    sr   t t| || |r"t||n|| _|d kr:t| j}t| 	|| _
dd | j
D | _| jrn| | j d S )Nc                 S   s   g | ]
}|j qS r#   )startpos).0tokr#   r#   r$   
<listcomp>   s     z&ASTTokens.__init__.<locals>.<listcomp>)superr7   r%   astparse_treer   r   list_translate_tokens_tokens_token_offsetsmark_tokens)r    r!   r?   treer"   tokens	__class__r#   r$   r%   p   s    
zASTTokens.__init__c                 C   s   ddl m} || | dS )ap  
    Given the root of the AST or Astroid tree produced from source_text, visits all nodes marking
    them with token and position information by adding ``.first_token`` and
    ``.last_token``attributes. This is done automatically in the constructor when ``parse`` or
    ``tree`` arguments are set, but may be used manually with a separate AST or Astroid tree.
    r   )
MarkTokensN)rE   rJ   Z
visit_tree)r    Z	root_noderJ   r#   r#   r$   rE      s    	zASTTokens.mark_tokensc           	      c   sd   t t|D ]R\}}|\}}}}}t||||||| j|d |d | j|d |d V  qdS )zS
    Translates the given standard library tokens into our own representation.
    r   r   N)	enumerater   r   r   r,   )	r    Zoriginal_tokensindexr;   tok_typetok_strr.   r/   liner#   r#   r$   rB      s    zASTTokens._translate_tokensc                 C   s   | j S )z,The source code passed into the constructor.)r   r    r#   r#   r$   text   s    zASTTokens.textc                 C   s   | j S )zIThe list of tokens corresponding to the source code from the constructor.)rC   rP   r#   r#   r$   rG      s    zASTTokens.tokensc                 C   s   | j S )zTThe root of the AST tree passed into the constructor or parsed from the source code.)r@   rP   r#   r#   r$   rF      s    zASTTokens.treec                 C   s   | j S )zThe filename that was parsed)r   rP   r#   r#   r$   r"      s    zASTTokens.filenamec                 C   s   | j t| j|d  S )z
    Returns the token containing the given character offset (0-based position in source text),
    or the preceeding token if the position is between tokens.
    r   )rC   bisectrD   )r    offsetr#   r#   r$   get_token_from_offset   s    zASTTokens.get_token_from_offsetc                 C   s   |  | j||S )z
    Returns the token containing the given (lineno, col_offset) position, or the preceeding token
    if the position is between tokens.
    )rT   r   r,   r    lineno
col_offsetr#   r#   r$   	get_token   s    	zASTTokens.get_tokenc                 C   s   |  || j||S )zd
    Same as get_token(), but interprets col_offset as a UTF8 offset, which is what `ast` uses.
    )rX   r   from_utf8_colrU   r#   r#   r$   get_token_from_utf8   s    zASTTokens.get_token_from_utf8c                 C   s2   |j d }|s(t| j| jr(|d7 }q| j| S )z
    Returns the next token after the given one. If include_extra is True, includes non-coding
    tokens from the tokenize module, such as NL and COMMENT.
    r   rL   r   rC   typer    r;   include_extrair#   r#   r$   
next_token   s
    

zASTTokens.next_tokenc                 C   s2   |j d }|s(t| j| jr(|d8 }q| j| S )z
    Returns the previous token before the given one. If include_extra is True, includes non-coding
    tokens from the tokenize module, such as NL and COMMENT.
    r   r[   r]   r#   r#   r$   
prev_token   s
    

zASTTokens.prev_tokenc                 C   s>   |}|r| j n| j}t|||s:t|js:||dd}q|S )z
    Looks for the first token, starting at start_token, that matches tok_type and, if given, the
    token string. Searches backwards if reverse is True. Returns ENDMARKER token if not found (you
    can check it with `token.ISEOF(t.type)`).
    Tr^   )ra   r`   r   tokenISEOFr\   )r    Zstart_tokenrM   rN   reversetZadvancer#   r#   r$   
find_token   s
    zASTTokens.find_tokenc                 c   s<   t |j|jd D ]$}|s*t| j| js| j| V  qdS )z
    Yields all tokens in order from first_token through and including last_token. If
    include_extra is True, includes non-coding tokens such as tokenize.NL and .COMMENT.
    r   N)r   rL   r   rC   r\   )r    first_token
last_tokenr^   r_   r#   r#   r$   token_range   s    
zASTTokens.token_rangec                 C   s   | j |j|j|dS )z
    Yields all tokens making up the given node. If include_extra is True, includes non-coding
    tokens such as tokenize.NL and .COMMENT.
    rb   )rj   rh   ri   )r    r)   r^   r#   r#   r$   
get_tokens   s    zASTTokens.get_tokensc                 C   sN   t |dsdS |jj}|jj}|rFtdd | |D rF|d df}||fS )r&   rh   r   r   rm   c                 s   s   | ]}t |tjV  qd S r   )r   rc   NEWLINE)r:   rf   r#   r#   r$   	<genexpr>  s     z/ASTTokens.get_text_positions.<locals>.<genexpr>r   )hasattrrh   r.   ri   r/   anyrk   r-   r#   r#   r$   r+     s    
zASTTokens.get_text_positions)FNr8   N)F)F)NF)F)F)r2   r3   r4   __doc__r%   rE   rB   propertyrQ   rG   rF   r"   rT   rX   rZ   r`   ra   rg   rj   rk   r+   __classcell__r#   r#   rH   r$   r7   \   s,   






 

r7   c                       sJ   e Zd ZdZd fdd	Zedd Zedd	 Zd
d Zdd Z	  Z
S )ASTTextaF  
  Supports the same ``get_text*`` methods as ``ASTTokens``,
  but uses the AST to determine the text positions instead of tokens.
  This is faster than ``ASTTokens`` as it requires less setup work.

  It also (sometimes) supports nodes inside f-strings, which ``ASTTokens`` doesn't.

  Some node types and/or Python versions are not supported.
  In these cases the ``get_text*`` methods will fall back to using ``ASTTokens``
  which incurs the usual setup cost the first time.
  If you want to avoid this, check ``supports_tokenless(node)`` before calling ``get_text*`` methods.
  Nr8   c                    s6   t t| || || _| jd k	r,t| j d | _d S r   )r=   ru   r%   r@   r   
_asttokens)r    r!   rF   r"   rH   r#   r$   r%   ,  s
    

zASTText.__init__c                 C   s,   | j d kr&t| j| j| _ t| j  | j S r   )r@   r>   r?   r   r   r   rP   r#   r#   r$   rF   9  s    

zASTText.treec                 C   s&   | j d kr t| j| j| jd| _ | j S )N)rF   r"   )rv   r7   r   rF   r   rP   r#   r#   r$   	asttokensA  s    
zASTText.asttokensc                 C   s  t jdd dk rtdt|r8d| jt| jfS t|dddkrLdS |sTtt|dg }|s|t|d	d}t|d
g }|r|d }n|}|j	}t
|}|r||j	ks||jkrt|ddrt|rd}n| j||j}||f}	tt|j}
tt|j}| j|
|}|
|f}|	|fS )zF
    Version of ``get_text_positions()`` that doesn't use tokens.
    N         zPThis method should only be called internally after checking supports_tokenless()rm   rV   rl   Zdecorator_list
decoratorsZnodesr   Zdoc_node)sysversion_infoAssertionErrorr   r   Zoffset_to_linelenr   getattrrV   r   
end_linenor   rY   rW   r	   intend_col_offset)r    r)   r*   r|   Zdecorators_nodeZ
start_nodeZstart_linenoZend_nodeZstart_col_offsetr.   r   r   r/   r#   r#   r$   _get_text_positions_tokenlessL  sB    

	z%ASTText._get_text_positions_tokenlessc                 C   s2   t |ddrdS t|r$| ||S | j||S )r&   Z_broken_positionsNrl   )r   supports_tokenlessr   rw   r+   r(   r#   r#   r$   r+     s
    zASTText.get_text_positions)Nr8   )r2   r3   r4   rr   r%   rs   rF   rw   r   r+   rt   r#   r#   rH   r$   ru     s   


Fru   r#   rx   ry   )	arguments	ArgumentsZwithitem)argZStarred)ZSliceZExtSliceZIndexkeywordc                 C   sd   t | jtkobt| tj o@| dk	o@t | jdko@t | jjdk obtjdd dkobdtj	
 kS )a  
  Returns True if the Python version and the node (if given) are supported by
  the ``get_text*`` methods of ``ASTText`` without falling back to ``ASTTokens``.
  See ``ASTText`` for why this matters.

  The following cases are not supported:

    - Python 3.7 and earlier
    - PyPy
    - ``ast.arguments`` / ``astroid.Arguments``
    - ``ast.withitem``
    - ``astroid.Comprehension``
    - ``astroid.AssignName`` inside ``astroid.Arguments`` or ``astroid.ExceptHandler``
    - The following nodes in Python 3.8 only:
      - ``ast.arg``
      - ``ast.Starred``
      - ``ast.Slice``
      - ``ast.ExtSlice``
      - ``ast.Index``
      - ``ast.keyword``
  NZ
AssignName)r   ZExceptHandlerrx   ry   pypy)r\   r2   _unsupported_tokenless_types
isinstancer>   ASTparentr}   r~   versionlower)r)   r#   r#   r$   r     s    
r   )N))r5   r>   rR   r}   rc   r   typingr   r   r   r   r   r   r	   r
   r   Z	six.movesr   Zline_numbersr   utilr   r   r   r   r   r   r   r   r   r   r   with_metaclassABCMetaobjectr   r7   ru   r   r~   r   r#   r#   r#   r$   <module>   s0   (,8 D 
