
    iJ<                     0   S r SSKrSSKrSSKJr  SSKJr  SSKJr  \	" \S\R                  5      r
S\4S jr\R                  \R                  -  4S	\4S
 jjrS	\S\4S jr\R$                  (       d  Sr\rSrSrSrSrS rO\R4                  (       d  SrSrSrSrSrSr\" S5      rS rO\Sr\r\R8                  (       a  SrOSrSr\R8                  (       a  SrOSrSr\R:                  (       a  \" S5      rS rO\" S5      rS r\" S\-   S -   \-   S!-   \-   S"-   \-   S#-   \-   S$-   \-   S%-   \-   S&-   \-   S'-   5      r\" S(\-   S)-   \-   S*-   5      rS+\4S, jr S-\S.\S/\4S0 jr!S-\S.\S/\"4S1 jr#S.\S/\"4S2 jr$S8S3\%S.\S/\&4S4 jjr'S.\S/\&4S5 jr(S6\4S7 jr)g)9aX  
Tools for searching bytecode for key statements that indicate the need for additional resources, such as data files
and package metadata.

By *bytecode* I mean the ``code`` object given by ``compile()``, accessible from the ``__code__`` attribute of any
non-builtin function or, in PyInstallerLand, the ``PyiModuleGraph.node("some.module").code`` attribute. The best
guide for bytecode format I have found is the disassembler reference: https://docs.python.org/3/library/dis.html

This parser implementation aims to combine the flexibility and speed of regex with the clarity of the output of
``dis.dis(code)``. It has not achieved the 2nd, but C'est la vie...

The biggest clarity killer here is the ``EXTENDED_ARG`` opcode which can appear almost anywhere and therefore needs
to be tiptoed around at every step. If this code needs to expand significantly, I would recommend an upgrade to a
regex-based grammar parsing library such as Reparse. This way, little steps like unpacking ``EXTENDED_ARGS`` can be
defined once then simply referenced forming a nice hierarchy rather than copied everywhere its needed.
    N)CodeType)Pattern)compat
_all_opmapxc                 P    [         R                  " [        [        U    /5      5      $ )z?
Get a regex-escaped opcode byte from its human readable name.
)reescapebytesopmap)r   s    HC:\des-py\RoboSAPF\venv\Lib\site-packages\PyInstaller\depend\bytecode.py_instruction_to_regexr   )   s     99UE!H:&''    patternc                     [        U [        5      (       d   e[        R                  " SS U 5      n [        R                  " XS9$ )a  
A regex-powered Python bytecode matcher.

``bytecode_regex`` provides a very thin wrapper around :func:`re.compile`.

  * Any opcode names wrapped in backticks are substituted for their corresponding opcode bytes.
  * Patterns are compiled in VERBOSE mode by default so that whitespace and comments may be used.

This aims to mirror the output of :func:`dis.dis`, which is far more readable than looking at raw byte strings.
s   `(\w+)`c                 :    [        U S   R                  5       5      $ )N   )r   decode)ms    r   <lambda> bytecode_regex.<locals>.<lambda>@   s    '!6r   )flags)
isinstancer   r	   subcompile)r   r   s     r   bytecode_regexr   0   sA     gu%%%% ff6G
 ::g++r   stringc              #     #    [        U[        5      (       d   e[        U5      nU R                  U5      n U HB  nUR	                  5       S-  S:X  a  Uv   M   U R                  XR	                  5       S-   5      n  O   gMK  7f)a  
Call ``pattern.finditer(string)``, but remove any matches beginning on an odd byte (i.e., matches where
match.start() is not a multiple of 2).

This should be used to avoid false positive matches where a bytecode pair's argument is mistaken for an opcode.
   r   r   N)r   r   _cleanup_bytecode_stringfinditerstart)r   r   matchesmatchs       r   r!   r!   F   s      fe$$$$%f-Fv&G
E{{}q A% "**6;;=13DE   s   B Bs   `EXTENDED_ARG`s%   `LOAD_NAME`|`LOAD_GLOBAL`|`LOAD_FAST`s   `LOAD_ATTR`|`LOAD_METHOD`s   `LOAD_CONST`s0   `CALL_FUNCTION`|`CALL_METHOD`|`CALL_FUNCTION_EX`c                     U $ N bytecodes    r   r    r    p   s    r   s#   `EXTENDED_ARG`|`EXTENDED_ARG_QUICK`s"   `EXTENDED_ARG``EXTENDED_ARG_QUICK`s   `PRECALL`|`CALL_FUNCTION_EX`s   (`CACHE`.)|(..)c                 .    [         R                  SU 5      $ Ns   \2_cache_instruction_filterr   r(   s    r   r    r       s    (,,VX>>r   s8   `LOAD_NAME`|`LOAD_GLOBAL`|`LOAD_FAST`|`LOAD_FAST_BORROW`s   `LOAD_ATTR`s3   `LOAD_CONST`|`LOAD_SMALL_INT`|`LOAD_CONST_IMMORTAL`s   `CALL`|`CALL_FUNCTION_EX`s   (`CACHE`.)|(`PUSH_NULL`.)|(..)c                 .    [         R                  SU 5      $ )Ns   \3r,   r(   s    r   r    r           ,00BBr   c                 .    [         R                  SU 5      $ r+   r,   r(   s    r   r    r       r/   r   s   
    # Matches `global_function('some', 'constant', 'arguments')`.

    # Load the global function. In code with >256 of names, this may require extended name references.
    (
     (?:(?:s   ).)*
     (?:(?:s   ).)
    )

    # For foo.bar.whizz(), the above is the 'foo', below is the 'bar.whizz' (one opcode per name component, each
    # possibly preceded by name reference extension).
    (
     (?:
       (?:(?:s   ).)*
       (?:s   ).
     )*
    )

    # Load however many arguments it takes. These (for now) must all be constants.
    # Again, code with >256 constants may need extended enumeration.
    (
      (?:
        (?:(?:s   ).)*
        (?:s   ).
      )*
    )

    # Call the function. If opcode is CALL_FUNCTION_EX, the parameter are flags. For other opcodes, the parameter
    # is the argument count (which may be > 256).
    (
      (?:(?:s   ).)*
      (?:s	   ).
    )
s:   (
    # Arbitrary number of EXTENDED_ARG pairs.
    (?:(?:sG   ).)*

    # Followed by some other instruction (usually a LOAD).
    [^s   ].
)extended_argsc                 :    [         R                  U SSS2   S5      $ )a9  
Unpack the (extended) integer used to reference names or constants.

The input should be a bytecode snippet of the following form::

    EXTENDED_ARG    ?      # Repeated 0-4 times.
    LOAD_xxx        ?      # Any of LOAD_NAME/LOAD_CONST/LOAD_METHOD/...

Each ? byte combined together gives the number we want.
r   Nr   big)int
from_bytes)r1   s    r   extended_argumentsr6      s      >>-1-u55r   rawcodereturnc                    [        U 5      nU S   [        S   :X  a  UR                  U   $ U S   [        S   :X  a  UR                  U   $ [        R
                  (       a"  U S   [        S   :X  a  UR                  US-	     $ [        R                  (       a"  U S   [        S   :X  a  UR                  US-	     $ [        R                  (       a  U S   [        S   :X  a  U$ [        R                  (       a  U S   [        S   :X  a  UR                  U   $ [        R                  (       a  U S   [        S	   :X  a  UR                  U   $ UR                  U   $ )
z+
Parse an (extended) LOAD_xxx instruction.
	LOAD_FAST
LOAD_CONSTLOAD_GLOBALr   	LOAD_ATTRLOAD_SMALL_INTLOAD_CONST_IMMORTALLOAD_FAST_BORROW)	r6   r   co_varnames	co_constsr   is_py311co_namesis_py312is_py314)r7   r8   indexs      r   loadrJ      s&   
 s#E
 2w%$$&&
2w%%%~~e$$3r7eM&::}}UaZ((3r7eK&88}}UaZ((3r7e,<&==3r7e,A&BB ~~e$$3r7e,>&?? &&==r   c                 j    [         R                  U 5       Vs/ s H  n[        X!5      PM     sn$ s  snf )z
Parse multiple consecutive LOAD_xxx instructions. Or load() in a for loop.

May be used to unpack a function's parameters or nested attributes ``(foo.bar.pop.whack)``.
)_extended_arg_bytecodefindallrJ   )r7   r8   is      r   loadsrO     s-     $:#A#A##FG#FaDM#FGGGs   0c                    / n[        [        U R                  5       H  nUR                  5       u  p4pV[	        X05      n[        X@5      nSR                  U/U-   5      n[        XP5      nUS   [        S   :X  aK  [        U5      nUS:w  a  Mo  [        U5      S:w  d  [        US   [        5      (       d  M  [        US   5      nO[        U5      n	U	[        U5      :w  a  M  UR                  Xu45        M     U$ )zB
Scan a code object for all function calls on constant arguments.
.r   CALL_FUNCTION_EXr   )r!   _call_function_bytecodeco_codegroupsrJ   rO   joinr   r6   lenr   tuplelistappend)
r8   outr$   function_rootmethodsargsfunction_callfunctionr   	arg_counts
             r   function_callsrb     s    
 C14<<@6;lln3 ]1&88]Og56T u%788&}5Ez 4yA~ZQ%?%?Q=D*=9ICI%

H#$; A> Jr   searchc                     Uc  0 nX;  a@  U " U5      X!'   UR                    H&  n[        U[        5      (       d  M  [        XU5        M(     U$ )ze
Apply a search function to a code object, recursing into child code objects (function definitions).
)rD   r   r   search_recursively)rc   r8   _memoconsts       r   re   re   B  sK     }Tl^^E%**"6%8 $ Lr   c                 "    [        [        U 5      $ )z
Scan a code object for function calls on constant arguments, recursing into function definitions and bodies of
comprehension loops.
)re   rb   )r8   s    r   recursive_function_callsri   P  s    
 nd33r   	full_namec              #      #    U R                  S5      nU(       a"  SR                  U5      v   USS nU(       a  M!  gg7f)a  List possible aliases of a fully qualified Python name.

    >>> list(any_alias("foo.bar.wizz"))
    ['foo.bar.wizz', 'bar.wizz', 'wizz']

This crudely allows us to capture uses of wizz() under any of
::
    import foo
    foo.bar.wizz()
::
    from foo import bar
    bar.wizz()
::
    from foo.bar import wizz
    wizz()

However, it will fail for any form of aliases and quite likely find false matches.
rQ   r   N)splitrV   )rj   partss     r   	any_aliasrn   X  s8     & OOC E
hhuoab	 %s   8>>r&   )*__doc__disr	   typesr   typingr   PyInstallerr   getattrr   strr   VERBOSEDOTALLr   r   r!   rE   _OPCODES_EXTENDED_ARG_OPCODES_EXTENDED_ARG2_OPCODES_FUNCTION_GLOBAL_OPCODES_FUNCTION_LOAD_OPCODES_FUNCTION_ARGS_OPCODES_FUNCTION_CALLr    rG   r-   rH   is_py313rS   rL   r6   rJ   rY   rO   rb   callabledictre   ri   rn   r'   r   r   <module>r      s  "  	   
 	\399-(S ( *,bii)? ,E ,,g u B .2H:-Q	
 DCH:-=
 !//B C?
 /2#_ #L , "Y!1: $23U$V!	C %33F$G!	C
 )
 ''
* **- )), ''*, *-*,--. (/(.+/< (=(<+=> &?&>)?!# L (%&)


 ##
& 6e 6$ e $ 8 $  $ NHu HH H H& &d &Rx x  48 4 4 r   