
bs\c           @  s   d  d l  m Z d  d l Z d  d l Z d  d l Z d  d l Z 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 m Z d  d l Z e j Z d Z e j   Z d Z d Z d e f d     YZ d	   Z d
 e f d     YZ d S(   i(   t   print_functionN(   t   loadst   dumpsi   s
   RENPY RPC2s   cache/bytecode.rpybt   ScriptErrorc           B  s   e  Z d  Z RS(   sa   
    Exception that is raised if the script is somehow inconsistent,
    or otherwise wrong.
    (   t   __name__t
   __module__t   __doc__(    (    (    s   renpy/script.pyR   8   s   c         C  s+   g  } x |  D] } | j  | j  q W| S(   sO   
    Returns a flat list containing every statement in the tree
    stmts.
    (   t   get_childrent   append(   t   stmtst   rvt   i(    (    s   renpy/script.pyt   collapse_stmts?   s    t   Scriptc           B  s   e  Z d  Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z	 d   Z
 d	 d
  Z e d d  Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z RS(   sk  
    This class represents a Ren'Py script, which is parsed out of a
    collection of script files. Once parsing and initial analysis is
    complete, this object can be serialized out and loaded back in,
    so it shouldn't change at all after that has happened.

    @ivar namemap: A map from the name of an AST node to the AST node
    itself.  This is used for jumps, calls, and to find the current
    node when loading back in a save. The names may be strings or
    integers, strings being explicit names provided by the user, and
    integers being names synthesised by renpy.

    @ivar initcode: A list of priority, Node tuples that should be
    executed in ascending priority order at init time.

    @ivar all_stmts: A list of all statements, that have been found
    in every file. Useful for lint, but tossed if lint is not performed
    to save memory.

    c         C  s  |  t  j _ t j j t  j j d  rM t t  j j d d  j	   |  _
 n	 d |  _
 i  |  _ g  |  _ g  |  _ g  |  _ g  |  _ t |  _ i  |  _ i  |  _ t |  _ t  j j   |  _ |  j   |  j   |  j j   d |  _ t j t  j   |  _! t |  _" g  |  _# g  |  _$ d S(   s   
        Loads the script by parsing all of the given files, and then
        walking the various ASTs to initialize this Script object.
        s	   /lock.txtt   rbi    N(%   t   renpyt   gamet   scriptt   ost   patht   existst   configt
   renpy_baset   filet   readt   keyt   Nonet   namemapt	   all_stmtst
   all_pycodet
   all_pyexprt   need_analysist   Truet   record_pycodet   bytecode_oldcachet   bytecode_newcachet   Falset   bytecode_dirtyt   translationt   ScriptTranslatort
   translatort   init_bytecodet   scan_script_filest   chain_translatest   serialt   hashlibt   md5t   version_onlyt   digestt
   loaded_rpyt   backup_listt   duplicate_labels(   t   self(    (    s   renpy/script.pyt   __init__c   s,    %										

			c         C  s   t  j r d  Sx- d d d g D] } t  j j |  r d  Sq Wd d  l } | j t  j j d  } | d  k rq d  St	 j
 j t  j j  } t  j	 j
 j t  j j |  t  j j |   } t  j j d |  | S(   Ns   script_version.txts   script_version.rpys   script_version.rpycit   backupss   Backing up script files to %r:(   R   t   mobileR   t   loadert   loadablet   __main__t   path_to_savesR   t   gamedirR   R   t   basenamet   basedirt   joint   exportst   fsencodet	   write_log(   R4   R   R:   R6   R=   t	   backupdir(    (    s   renpy/script.pyt   choose_backupdir   s    	c   	      C  s  |  j  } g  |  _  t j j d d  d k r1 d  S|  j s> d  St j rK d  S|  j   } | d  k rg d  Sx| D]\ } } | j	 t j
 j  s qn n  t j j |  s qn n  t j j | t t j
 j  d  } t j j |  \ } } t j j | | d | d  j d  |  } t j j |  r1qn n  y  t j t j j |  d  Wn n Xy t j | |  Wqn qn Xqn Wd  S(	   Nt   RENPY_DISABLE_BACKUPSt    s   I take responsibility for this.i   t   .i   t   hexi  (   R2   R   t   environt   getR1   R   R7   RD   R   t
   startswithR   R<   R   R   R@   RA   t   lent   splitextR?   t   encodet   makedirst   dirnamet   shutilt   copy(	   R4   R2   RC   t   fnt   checksumt   short_fnt   baset   extt	   target_fn(    (    s   renpy/script.pyt   make_backups   s>    				&	" c         C  s  t  j j   } g  |  _ g  |  _ x | D] \ } } | j d  rk | d k rU q( n  | d  } |  j } n | j d  r | d  } |  j } n_ | j d  r | d k r q( n  | d  } |  j } n( | j d  r( | d  } |  j } n q( | | f | k r( | j | | f  q( q( Wd S(	   s8   
        Scan the directories for script files.
        s   .rpyis   .rpycis   .rpyms   .rpymciN(   R   R8   t   listdirfilest   script_filest   module_filest   endswithR   R   (   R4   t   dirlistt   dirRS   t   target(    (    s   renpy/script.pyR*      s.    		



c   	      C  s   |  j  } | j   g  } xR | D]J \ } } t j rQ d d  l } | j d  n  |  j d d | | |  q  Wg  t |  D]! \ } \ } } | | | f ^ q{ } | j   g  | D] \ } } } | | f ^ q |  _ |  j j	   d  S(   Nii    s   .rpycs   .rpy(
   R[   t   sortR   t
   emscriptent   sleept   load_appropriate_filet	   enumeratet   initcodeR(   R+   (	   R4   R[   Rf   RS   R_   Rb   t   indext   priot   code(    (    s   renpy/script.pyt   load_script   s    	
	1
+c         C  s   g  |  j  D]$ \ } } | | k r
 | | f ^ q
 } | sM t d |   n  t |  d k rr t d |   n  | d \ } } g  } |  j d d | | |  t j j   r t d   n  |  j j	   | S(   Ns   Module %s could not be loaded.i   s-   Module %s ambiguous, multiple variants exist.i    s   .rpymcs   .rpymi(
   R\   t	   ExceptionRL   Rd   R   t   parsert   report_parse_errorst
   SystemExitR(   R+   (   R4   t   nameRS   R_   t   filesRf   (    (    s   renpy/script.pyt   load_module  s    4c         C  si   t  |  } t t j    } xD | D]< } | j d  k r% | | |  j f | _ |  j d 7_ q% q% Wd  S(   Ni   (   R   t   intt   timeRo   R   R,   (   R4   R	   RS   R   t   versiont   s(    (    s   renpy/script.pyt   assign_names1  s    c         C  s   t  |  } t  |  } g  | D] } | j   ^ q } g  | D] } | j   ^ q> } t j d  | |  } xn | j   D]` \ } } }	 xN t |	  D]@ } | | | }
 | | | } | j d  k r |
 j | _ q q Wqx Wd  S(   N(   R   t	   diff_infot   difflibt   SequenceMatcherR   t   get_matching_blockst   rangeRo   (   R4   t	   old_stmtst	   new_stmtsR   t   old_infot   new_infot   smt   oldlt   newlt   countt   oldt   new(    (    s   renpy/script.pyt   merge_names=  s    i   c         C  sm   t  j j | | d | } | d k r+ d S|  j | |  |  j |  g  } |  j | | t  } | | f S(   s9  
        Loads Ren'Py script from a string.

        `filename`
            The filename that's assigned to the data.

        `filedata`
            A unicode string to be loaded.

        Return the list of statements making up the root block, and a
        list of init statements that need to be run.
        t
   linenumberN(   NN(   R   Rl   t   parseR   Rv   t   static_transformst   finish_loadR$   (   R4   t   filenamet   filedataR   R	   Rf   (    (    s   renpy/script.pyt   load_stringO  s    c           s  | s
 | St  j j | d  g  } x | D] } | j | j  q* W j j |  | d k	 r t  j j	 |  } | d j
 j   j | j    s | d d k r | d 7} n  x | D] } | | _
 q Wq n     f d   }  j   xr | D]j } | j }	 | |  |  j |	 <| j rH| j   }
 |
 rH| j |
  qHn  | j r | j   q q W j d k	 r j j |  n   j j |  | S(   s  
        Given `stmts`, a list of AST nodes comprising the root block,
        finishes loading it.

        `initcode`
            A list we append init statements to.

        `check_names`
            If true, produce duplicate name errors.

        `filename`
            If given, a filename that overrides the filename found inside the
            file.

        Returns a list of statements that corresponds to the top-level block
        in initcode after transformation.
        i    it   cc           s     s
 d  St  j r d  Sd  } d  } d  } |  j } |  j k r | } |  }  j | } t | t  s t d t |  | j	 | j
 | j	 | j
 f   q t  j j r d  S j j d j | | j	 | j
 | j	 | j
   n  d  S(   Ns-   Name %s is defined twice, at %s:%d and %s:%d.uP   The label {} is defined twice, at
  File "{}", line {} and
  File "{}", line {}.(   R   R7   R   Ro   R   t
   isinstancet
   basestringR   t   reprR   R   R   t   allow_duplicate_labelsR3   R   t   format(   t   nodet   bad_namet   bad_nodet   old_nodeRo   (   t   check_namesR4   (    s   renpy/script.pyt
   check_name  s,    				N(   R   t   astt   chain_blockR   R   R   R(   t   take_translatesRl   t   elide_filenameR   t   lowerR]   t   update_bytecodeRo   R   t   get_initt   early_executeR   t   extendR   (   R4   R	   Rf   R   R   R   R   R   R   Ro   t   init(    (   R   R4   s   renpy/script.pyR   k  s<    "$
	
		c         C  sG   | j  t  x3 t d  D]% } | j  t j d d d d   q Wd S(   sU   
        Writes an empty version 2 .rpyc header to the open binary file `f`.
        i   t   IIIi    N(   t   writet   RPYC2_HEADERR{   t   structt   pack(   R4   t   ft   _i(    (    s   renpy/script.pyt   write_rpyc_header  s    c         C  s   | j  d d  | j   } t j | d  } | j |  | j  t t  d | d d  | j t j d | | t |    | j  d d  d S(   s   
        Writes data into `slot` of a .rpyc file. The data should be a binary
        string, and is compressed before being written.
        i    i   i	   i   i   R   N(	   t   seekt   tellt   zlibt   compressR   RL   R   R   R   (   R4   R   t   slott   datat   start(    (    s   renpy/script.pyt   write_rpyc_data  s    "%c         C  s!   | j  d d  | j |  d S(   s<   
        Writes the md5 to the end of a .rpyc file.
        i    i   N(   R   R   (   R4   R   R0   (    (    s   renpy/script.pyt   write_rpyc_md5  s    c   	      C  s   | j  d  } | t t   t k r[ | d k r5 d S| j d  | j    } | j d  St t  } xZ t r t j d | | | d ! \ } } } | | k r Pn  | d k r d S| d 7} qj W| j |  | j  |  } t	 j
 |  S(   s   
        Reads the binary data from `slot` in a .rpyc (v1 or v2) file. Returns
        the data if the slot exists, or None if the slot does not exist.
        i   i   i    R   R   i   N(   R   RL   R   R   R   t   decodeR    R   t   unpackR   t
   decompress(	   R4   R   R   t   header_dataR   t   post   header_slotR   t   length(    (    s   renpy/script.pyt   read_rpyc_data  s$    	&c         C  s   t  j j |  d S(   s   
        This performs transformations on the script that can be performed
        statically. When possible, these transforms are stored in slot 2
        of the rpyc file.
        N(   R   R&   t   restructure(   R4   R	   (    (    s   renpy/script.pyR   $  s    c         C  su  | j  d  s | j  d  r*| s7 t d |   n  | d | } | d } t j j |  } i  } t | d <|  j p} d | d <| d  k r | g  f Szm y_ t |  _	 t
 | d	   } |  j | d
  } Wd  QXt |  \ }	 }
 |  j |
 |  ~	 ~
 Wn n XWd  t |  _	 X|  j | t j j |   t j syB t | d  } |  j |  |  j | d
 t | | f d   WqqXn  |  j |  t j sys |  j | d t | | f d   t
 | d  " } t j | j    j   } Wd  QX|  j | |  | j   WqqXn  t |  _ nA| j  d  sH| j  d  rgd  } d  } t j j |  } z xa d d
 g D]O } y2 |  j | |  } | rt |  \ } } Pn  Wn n X| j  d  qvWd S| d  k rt! d |  d St" | t#  sd S|  j r%| j$ d d  |  j k r%d S| d t k r9d S| d k  rU|  j |  n  Wd  | j   Xn d S| | f S(   Ns   .rpys   .rpyms4   Cannot load rpy/rpym file %s from inside an archive.t   /R   Rt   t   unlockedR   R   i   t   wbi   t   rUs   .rpycs   .rpymci    s   Failed to load(   NN(   NN(   NN(   NN(   NN(   NN(%   R]   Rk   R   Rl   R   t   script_versionR   R   R$   R!   t   openR   R   R   R    Rv   R   t   macappR   R   R   R   R   R-   R.   R   R0   R   t   closeR1   R8   t   loadR   t   printR   t   dictRJ   (   R4   R_   RS   t   fullfnt   rpycfnR	   R   t   rpycft   bindatat   old_dataR|   R   t   fullft	   rpydigestR   (    (    s   renpy/script.pyt	   load_file.  s    


 	
	&	"!$c         C  s  | d  k r | | } | | } |  j | | |  \ } }	 | d  k r^ t d | f   n  t j j | |  }
 |
 j t j   j	 d  |
 j
 t j   j	  } |
 j   n| d | | } | d | | } t j j |  t j j |  r/t | d  " }
 t j |
 j
    j   } Wd  QXn d  } yi t j j |  rt | d  9 }
 |
 j t j   j	 d  |
 j
 t j   j	  } Wd  QXn d  } Wn d  } n Xd  } t j j |  rt j j |  rt j j j } | } d \ } }	 yS | | k rK| rK|  j | | |  \ } }	 | d  k rKt d |  qKn  Wn) d t j k rxt d |    qxn X| d  k r|  j | | |  \ } }	 n  | } nz t j j |  r| } |  j | | |  \ } }	 | } n= t j j |  r&| } |  j | | |  \ } }	 | } n  | d  k	 rK|  j j | | f  n  | d  k rjt d	 |   n  |  j d  k r| d
 |  _ n& |  j | d
 k rt | d   n  |  j |	 | d | |  j j |  d  S(   Ns   Could not load from archive %s.i   R   R   R   s   Could not load t   RENPY_RPYC_EXCEPTIONSs   While loadings   Could not load file %s.R   s{    does not share a key with at least one .rpyc file. To fix, delete all .rpyc files, or rerun Ren'Py with the --lock option.R   (   NN(   R   R   Rk   R   R8   R   R   R-   R.   t   digest_sizeR   R   t   add_autoR   R   R   R   R0   R   t   argst   compileR   RI   R2   R   R   R   t   update(   R4   t   compiledt   sourceR_   RS   Rf   t   rpyfnt   lastfnR   R	   R   R0   R   R   t
   rpycdigestt   force_compile(    (    s   renpy/script.pyRd     sz    

$!

$			c         C  sW   yI t  t j j t  j   j d   \ } } | t k rH | |  _ n  Wn n Xd S(   s0   
        Init/Loads the bytecode cache.
        R   N(	   R   R   R8   R   t   BYTECODE_FILER   R   t   BYTECODE_VERSIONR"   (   R4   Rt   t   cache(    (    s   renpy/script.pyR)     s    -c         C  sp  x2 |  j  D]' } y t j j | d  Wq
 q
 Xq
 Wg  |  _  x"|  j D]} | j   t } |  j j | d  } | d k r@t
 |  _ t j j } d | j d | j d f t j _ y | j d k r t j j | j d | j d d | j d } n | j d k r=t j j | j d | j d d | j d } nA | j d k r~t j j | j d | j d d | j d } n  Wn t k
 r0} | j } | d k rd	 } n  y | j d
  } Wn | j d  } n Xt j j d | j d | j d | j d | d | j  } t j j j | j  qH n X| t j _ n  | |  j  | <t! j" |  | _# qH Wg  |  _ d S(   sy   
        Compiles the PyCode objects in self.all_pycode, updating the
        cache. Clears out self.all_pycode.
        t   evals7   While compiling python block starting at line %d of %s.i   i    t   execR   t   linenot   hideRF   s   utf-8s   latin-1t   numbert   msgt   lineR   N($   R   R   t   pythont
   py_compileR   t   get_hasht   MAGICR"   RJ   R   R    R%   R   t   exception_infot   locationt   modet   py_compile_exec_bytecodeR   t   py_compile_hide_bytecodet   py_compile_eval_bytecodet   SyntaxErrort   textR   Rl   t
   ParseErrorR   R   R   t   offsett   parse_errorsR   t   messageR#   t   marshalR   t   bytecode(   R4   R   R   Ri   t   old_eit   eR   t   pem(    (    s   renpy/script.pyR     sP    		$226					c         C  s   t  j r d  S|  j r y\ t  j j t  } t | d  5 } t |  j f } | j	 t
 | d  j d   Wd  QXWq q Xn  d  S(   NR   i   R   (   R   R   R%   R8   t   get_pathR   R   R   R#   R   R   RN   (   R4   RS   R   R   (    (    s   renpy/script.pyt   save_bytecode]  s    		)c         C  s   t  | t j j  r( | j d j } n  t j j j | |  } | } |  j	 j | d  } | d k r t j j d k	 r t j j |  } |  j	 j | d  } n  | d k r t d t |    n  |  j	 | S(   sp   
        Looks up the given label in the game. If the label is not found,
        raises a ScriptError.
        i    s   could not find label '%s'.N(   R   R   Rl   t   SubParset   blockRo   R   t   label_overridesRJ   R   R   t   missing_label_callbackR   t   str(   R4   t   labelt   originalR
   (    (    s   renpy/script.pyt   lookupk  s    c         C  sZ   t  | t j j  r5 | j s" t S| j d j } n  t j j j	 | |  } | |  j
 k S(   sG   
        Returns true if the label exists, or false otherwise.
        i    (   R   R   Rl   R   R   R$   Ro   R   R   RJ   R   (   R4   R  (    (    s   renpy/script.pyt	   has_label  s    	c         C  s0   | d k r d S|  j |  s# d S|  j |  S(   sR   
        Looks up the label if it exists, or returns None if it does not.
        N(   R   R  R  (   R4   R  (    (    s   renpy/script.pyt   lookup_or_none  s
    c         C  s+   x |  j  D] } | j   q
 Wg  |  _  d S(   s=   
        Analyzes all statements that need analysis.
        N(   R   t   analyze(   R4   R   (    (    s   renpy/script.pyR    s    c         C  sQ   t  j j s d  St  j j r  d  S|  j t  j _ t  j j   rM t d   n  d  S(   Ni(	   R   R   t	   developert   ignore_duplicate_labelsR3   Rl   R   Rm   Rn   (   R4   (    (    s   renpy/script.pyt   report_duplicate_labels  s    N(   R   R   R   R5   RD   RY   R*   Rj   Rq   Rv   R   R   R    R   R   R   R   R   R   R   R   Rd   R)   R   R   R  R  R  R  R  (    (    (    s   renpy/script.pyR   M   s4   	.		/	)				n	
			(	
	u	h		D					
(   t
   __future__R    R   R-   R   t   impRx   Rs   R   R   R   t   cPickleR   R   RQ   R   R   t	   get_magicR   R   R   Rk   R   R   t   objectR   (    (    (    s   renpy/script.pyt   <module>   s&   		