
!\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 e e e   Z e   Z d a d a d   Z i  Z d   Z d d  Z d d  Z e   Z d   Z e   Z d   Z e d	  Z i  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- d   Z. d   Z/ d   Z0 d   Z1 d   Z2 d   Z3 d   Z4 d    Z5 d!   Z6 d" e7 f d#     YZ8 d$   Z9 d%   Z: d S(&   i(   t   print_functionNc         G  s]   t  r+ d t j j t  j  t  j f } n d } | |  | 7} t   t | j d   d  S(   Nu   %s:%d t    s   utf-8(   t   report_nodet   renpyt   parsert   unicode_filenamet   filenamet
   linenumbert   printt   encode(   t   msgt   argst   out(    (    s   renpy/lint.pyt   report9   s    %c         C  s6   |  t  k r2 t t  |  <t t |   j d   n  d  S(   Ns   utf-8(   t   addedt   TrueR   t   unicodeR	   (   R
   (    (    s   renpy/lint.pyt   addJ   s    
c         C  s   t  |  |  t j d |  } | s) d St t j | j d   rH d S| j d  t k ra d St d | |   | r t	 |  n  d S(   s  
    :doc: lint

    Tries to evaluate an expression, and writes an error to lint.txt if
    it fails.

    `where`
        A string giving the location the expression is found. Used to
        generate an error message of the form "Could not evaluate `expr`
        in `where`."

    `expr`
        The expression to try evaluating.

    `additional`
        If given, an additional line of information that is addded to the
        error message.
    s   \s*([a-zA-Z_]\w*)Ni   s   Could not evaluate '%s', in %s.(
   t   try_compilet   ret   matcht   hasattrR   t   storet   groupt   __builtins__R   R   (   t   wheret   exprt
   additionalt   m(    (    s   renpy/lint.pyt   try_evalQ   s    c         C  sE   y t  j j |  Wn* t d | |   | rA t |  qA n Xd S(   s  
    :doc: lint

    Tries to compile an expression, and writes an error to lint.txt if
    it fails.

    `where`
        A string giving the location the expression is found. Used to
        generate an error message of the form "Could not evaluate `expr`
        in `where`."

    `expr`
        The expression to try compiling.

    `additional`
        If given, an additional line of information that is addded to the
        error message.
    s6   '%s' could not be compiled as a python expression, %s.N(   R   t   pythont   py_compile_eval_bytecodeR   R   (   R   R   R   (    (    s   renpy/lint.pyR   }   s    c   	      C  sd  |  t  k r t S|  d } t   } t   } xC |  d D]7 } | d d k ra | j | d  q7 | j |  q7 Wx t j j j j   D] \ } } | d | k r q n  t | d  } g  | D] } | | k r | ^ q r q n  t	 | d d  } | d k	 r#| t | | d |   B} n  g  | D] } | | k r*| ^ q*rNq n  t  j |   t SWt S(   s   
    Returns true if the image is a plausible image that can be used in a show
    statement. This returns true if at least one image exists with the same
    tag and containing all of the attributes (and none of the removed attributes).
    i    i   t   -t   _list_attributesN(   t   imprecise_cacheR   t   setR   R   t   displayt   imaget   imagest   itemst   getattrt   Nonet   False(	   t   namet   nametagt   requiredt   bannedt   it   imt   dt   attrst   li(    (    s   renpy/lint.pyt   image_exists_imprecise   s.    
		"% %c           s}  |  t  k r t S|  d } t   } t   } xC |  d D]7 } | d d k ra | j | d  q7 | j |  q7 Wxt j j j j   D] \ } } | d | k r q n  t | d      | r q n  |     rgy} t j j	 j
   } | d f t   f d   |  d D  | _ t  f d   |  d D  | _ t | _ | j |  Wqgq qgXn  t  j |   t SWt S(   s   
    Returns true if an image exists with the same tag and attributes as
    `name`. (The attributes are allowed to occur in any order.)
    i    i   R    c         3  s!   |  ] } |   k r | Vq d  S(   N(    (   t   .0R/   (   R2   (    s   renpy/lint.pys	   <genexpr>   s    c         3  s!   |  ] } |   k r | Vq d  S(   N(    (   R5   R/   (   t   rest(    s   renpy/lint.pys	   <genexpr>   s    (   t   precise_cacheR   R#   R   R   R$   R%   R&   R'   t   coret   DisplayableArgumentst   tupleR+   R   t   lintt
   _duplicateR*   (   R+   R,   R-   R.   R/   R0   R1   t   da(    (   R2   R6   s   renpy/lint.pyt   image_exists_precise   s8    
		"

.#	
c         C  sm   | p |  d } t  t | <| r$ d S| s= t |   r= d Sn  t |   rM d St d j d j |     d S(   s?   
    Checks a scene or show statement for image existence.
    i    Ns   '{}' is not an image.t    (   R   t   image_prefixesR4   R>   R   t   formatt   join(   R+   t
   expressiont   tagt   precise(    (    s   renpy/lint.pyt   image_exists  s    
c         C  s   t  j | d   } | t k r" d  S| t k rH t d |  j   |  d  St j j	 |  s~ t d |  j   |  t t  | <d  St t  | <d  S(   Ns)   %s uses file '%s', which is not loadable.(
   t   check_file_cachet   getR)   R   R*   R   t
   capitalizeR   t   loadert   loadable(   t   whatt   fnt   present(    (    s   renpy/lint.pyt
   check_file  s    
c           s     f d   } | t  j j _ g    y/ t | t  j j j  rR | j d    n  Wn n Xx   D] } t |  |  qd Wd  S(   Nc           s     j  |  j    d  S(   N(   t   extendt   predict_files(   t   img(   t   files(    s   renpy/lint.pyt   predict_image0  s    c         S  s
   |  j    S(   N(   t   predict_one(   t   a(    (    s   renpy/lint.pyt   <lambda>9  s    (	   R   R$   t   predictR%   t
   isinstanceR8   t   Displayablet	   visit_allRO   (   RL   R1   RT   RM   (    (   RS   s   renpy/lint.pyt   check_displayable.  s    c         C  s7   d j  |  j  } t d | t j j j |  j  d  S(   NR?   s   image %s(   RB   t   imgnameR\   R   R$   R%   R&   (   t   nodeR+   (    (    s   renpy/lint.pyt   check_imageB  s    c         C  s   t  |   d k r4 |  d d  d  |  d |  d d f St  |   d k rw |  d |  d |  d |  d |  d |  d d  f S|  Sd  S(   Ni   i    i   i   i   i   i   (   t   lenR)   (   t   t(    (    s   renpy/lint.pyt   imspecI  s
    "1c   
      C  s   |  j  s d  St  |  j   \ } } } } } } } t j j | | pF |  } | t j j k r | t j j k r t d |  n  t | | | d | x | D] }	 t	 d |	 d  q Wd  S(   Ns/   Uses layer '%s', which is not in config.layers.RE   s'   the at list of a scene or show statments7   Perhaps you forgot to define or misspelled a transform.(
   Rb   R   t   exportst   default_layert   configt   layerst
   top_layersR   RF   R   (
   R^   RE   R+   RC   RD   t   at_listt   layert   _zordert   _behindR/   (    (    s   renpy/lint.pyt
   check_showS  s    	$$c         C  s.   |  j  s d  St  |  j   d } t t | <d  S(   Ni   (   Rb   R   R@   (   R^   RD   (    (    s   renpy/lint.pyt   precheck_showf  s    	c         C  s   t  |  j   \ } } } } } } } | p1 | d } t j j | |  } | t j j k r} | t j j k r} t d |  n  | t k r t d |  n  d  S(   Ni    s/   Uses layer '%s', which is not in config.layers.sy   The image tag '%s' is not the prefix of a declared image, nor was it used in a show statement before this hide statement.(	   Rb   R   Rc   Rd   Re   Rf   Rg   R   R@   (   R^   R+   t   _expressionRD   t   _at_listRi   Rj   Rk   (    (    s   renpy/lint.pyt
   check_hideq  s    $$c         C  s   t  d |  j d  d  S(   Ns   a with statement or clauses;   Perhaps you forgot to declare, or misspelled, a transition?(   R   R   (   R^   (    (    s   renpy/lint.pyt
   check_with  s    c         C  sa   d   } t  j j |  z |  j d  Wd  t  j j   Xy |  j   Wn t d  n Xd  S(   Nc         S  s   t  d |   d  S(   Ns   %s(   R   (   R
   (    (    s   renpy/lint.pyt   error  s    R;   s9   Didn't properly report what the next statement should be.(   R   Rc   t   push_error_handlert   callt   pop_error_handlert   get_nextR   (   R^   Rr   (    (    s   renpy/lint.pyt
   check_user  s    	c         C  s  t  j j j |   } | r8 t d | t |   d  n  d |  k rt  j j rd } d } d } x | t |   k  r^|  | } | d 7} | d k r | d k r[d } d } q[qe | d k r-| | 7} | d k r d } q[| d k r d } q[| d	 k r
d } q[t d
 | t |   d  d } qe | d k re | | 7} | d k r[d } q[qe qe W| d k rt d | t |   d  qn  d  S(   Ns
   %s (in %s)i   t   %i    R   t   (i   s   #0123456780- +hlLs   diouxXeEfFgGcrs%s'   Unknown string format code '%s' (in %s)t   )s,   Unterminated string format code '%s' (in %s)(	   R   t   textt   extrast   check_text_tagsR   t   reprRe   t   old_substitutionsR`   (   t   sR
   t   statet   post   fmtt   c(    (    s   renpy/lint.pyt   text_checks  s<    


				
c         C  s+  |  j  rO y t j j |  j   } WqO t d |  j   t d  d  } qO Xn  |  j rn t d |  j d  n  t	 |  j
  |  j s d  S|  j  d  k r d  St | t j j  s d  S|  j d  k r d  S| j d  k r d  S| j f |  j } t |  r d  St d |  rd  St d d j |   d  S(	   Ns;   Could not evaluate '%s' in the who part of a say statement.s)   Perhaps you forgot to define a character?s"   the with clause of a say statements;   Perhaps you forgot to declare, or misspelled, a transition?t   sidesG   Could not find image (%s) corresponding to attributes on say statement.R?   (   R   (   t   whoR   t   astt   eval_whoR   R   R)   t   with_R   R   RL   t   who_fastRY   t	   charactert   ADVCharactert
   attributest	   image_tagR4   RB   (   R^   t   charR+   (    (    s   renpy/lint.pyt	   check_say  s4    	
		c         C  s   |  j  r t d |  j  d  n  g  |  j D]$ \ } } } | r) | | | f ^ q) s` t d  n  x: |  j D]/ \ } } } | r t d |  n  t |  qj Wd  S(   Ns#   the with clause of a menu statements;   Perhaps you forgot to declare, or misspelled, a transition?s1   The menu does not contain any selectable choices.s   in the if clause of a menuitem(   R   R   R'   R   R   R   (   R^   t   lR   t   b(    (    s   renpy/lint.pyt
   check_menu  s    	4c         C  s<   |  j  r d  St j j j |  j  s8 t d |  j  n  d  S(   Ns&   The jump is to nonexistent label '%s'.(   RC   R   t   gamet   scriptt	   has_labelt   targetR   (   R^   (    (    s   renpy/lint.pyt
   check_jump  s    	c         C  s<   |  j  r d  St j j j |  j  s8 t d |  j  n  d  S(   Ns&   The call is to nonexistent label '%s'.(   RC   R   R   R   R   t   labelR   (   R^   (    (    s   renpy/lint.pyt
   check_call  s    	c         C  s   t  d |  j  d  S(   Ns'   in the condition of the while statement(   R   t	   condition(   R^   (    (    s   renpy/lint.pyt   check_while  s    c         C  s+   x$ |  j  D] \ } } t d |  q
 Wd  S(   Ns"   in a condition of the if statement(   t   entriesR   (   R^   R   t   _block(    (    s   renpy/lint.pyt   check_if  s    c         C  sz   |  j  d k r d  S|  j t j j k r, d  S|  j t k rQ t d | |  j  n  |  j t k rv t d | |  j  n  d  S(   NR   sB   '%s %s' replaces a python built-in name, which may cause problems.sB   '%s %s' replaces a Ren'Py built-in name, which may cause problems.(   R   t   varnameR   Re   t   lint_ignore_replacest   python_builtinsR   t   renpy_builtins(   R^   t   kind(    (    s   renpy/lint.pyt   check_define  s    c   
      C  s   | j  s& t d j |  |  |  d  St j j   d   } | t j j  } x | t j j j | g    D] } x | D]w } | t	 |  } | t j j
 k rz | j j d |  } | j |  }	 |	 j   t d j |  | |  |	  Pqz qz Wqm Wd  S(   Ns   {}, property {}c         S  s#   t  |   }  |  j d d    |  S(   Nt   keyc         S  s
   t  |   S(   N(   R`   (   RV   (    (    s   renpy/lint.pyRW   /  s    (   t   listt   sort(   R   (    (    s   renpy/lint.pyt
   sort_short-  s    t   prefix(   t   _duplicatableR\   RA   R   t   stylet   init_inspectt   prefix_altst   affectsRH   R`   t   all_propertiest   _argst   copyR<   t   _unique(
   R+   t   propertyR1   R   t   altst   pR   R6   R   t   dd(    (    s   renpy/lint.pyt    check_style_property_displayable#  s&    		%
c         C  s   x | j  D] } x | j   D] \ } } | j d  r t | t j j j  r x: t | j	 j
    D] } t |  |  qf Wq t |  |  n  t | t j j j  r t |  | |  q q Wq
 Wd  S(   Nt   font(   t
   propertiest	   iteritemst   endswithRY   R   R{   R   t	   FontGroupR#   t   mapt   valuesRO   R$   R8   RZ   R   (   R+   R   R   t   kt   vt   f(    (    s   renpy/lint.pyt   check_styleE  s    c         C  s]   d   } |  j  } | d  k	 rY x | j D] } | |  q( W| | j  | | j  n  d  S(   Nc         S  s<   |  d  k r d  St t j |   s8 t t j |  d   n  d  S(   N(   R)   R   R   R   t   setattr(   t   n(    (    s   renpy/lint.pyt   add_argX  s    (   t
   parametersR)   t
   positionalt   extrapost   extrakw(   R^   R   t   piR/   (    (    s   renpy/lint.pyt   check_labelV  s    		c         C  sW   |  j  j d  k rS t j j rS t d j |  j  j   t	 d j |  j  j   n  d  S(   Ns2   The screen {} has not been given a parameter list.s4   This can be fixed by writing 'screen {}():' instead.(
   t   screenR   R)   R   Re   t   lint_screens_without_parametersR   RA   R+   R   (   R^   (    (    s   renpy/lint.pyt   check_screeni  s    c          C  sn   xg t  j j j   D]S \ }  } d |  d } x% |  d D] } | d j |  7} q8 Wt d | |  q Wd  S(   Ns   style.i    i   s   [{!r}]s   Style (   R   R   t   stylesR   RA   R   (   t	   full_nameR   R+   R/   (    (    s   renpy/lint.pyt   check_stylesp  s
    c         C  sv   t  |   } g  } xT t t |   D]@ \ } } | rU | d rU | j d d  n  | j d |  q% Wd j |  S(   Ni   i    t   ,R   (   t   strt	   enumeratet   reversedt   insertRB   (   R   R   t   rvR/   R   (    (    s   renpy/lint.pyt   humanizey  s    c          C  sY   xR t  j j   D]A \ }  } y | j d  w Wn n Xt d |  t d  q Wd S(   sF   
    Checks files to ensure that they are displayable in unicode.
    t   asciis1   %s contains non-ASCII characters in its filename.sC   (ZIP file distributions can only reliably include ASCII filenames.)N(   R   RJ   t   listdirfilesR	   R   R   (   t   _dirnameR   (    (    s   renpy/lint.pyt   check_filename_encodings  s    t   Countc           B  s    e  Z d  Z d   Z d   Z RS(   s2   
    Stores information about the word count.
    c         C  s   d |  _  d |  _ d |  _ d  S(   Ni    (   t   blockst   wordst
   characters(   t   self(    (    s   renpy/lint.pyt   __init__  s    		c         C  sC   |  j  d 7_  |  j t | j    7_ |  j t |  7_ d  S(   Ni   (   R   R   R`   t   splitR   (   R   R   (    (    s   renpy/lint.pyR     s    (   t   __name__t
   __module__t   __doc__R   R   (    (    (    s   renpy/lint.pyR     s   	
c         C  s?   |  j  j d d  } | j d  s3 | j d  r7 t St Sd S(   s>   
    Returns true if the node is in the common directory.
    s   \t   /s   common/s   renpy/common/N(   R   t   replacet
   startswithR   R*   (   R   R   (    (    s   renpy/lint.pyt   common  s    c            s  t  j j d d d t  }  |  j d d d d d d	 d
 |  j   } | j rm t | j d  } | t _	 n  t
 t  j _ t t j  t t t  j d t j    j d   i  a x% t  j j j D] } t
 t | d <q Wg  t  j j j D] } | j | j | f ^ q } | j   t j t    d } d } d } d }	 xE | D]= \ }
 } } t! | t  j" j# t  j" j$ f  rGt% |  qGqGWx| D]\ }
 } } t& |  rqn  | a' t! | t  j" j(  r|	 d 7}	 t) |  qt! | t  j" j#  rt* | t  qt! | t  j" j$  r,t* | t
  qt! | t  j" j+  rNt, |  qt! | t  j" j-  rpt. |  qt! | t  j" j/  rt0 |    | j1 | j2  qt! | t  j" j3  rt4 |  | d 7} qt! | t  j" j5  rt6 |  qt! | t  j" j7  rt8 |  qt! | t  j" j9  r8t: |  qt! | t  j" j;  rZt< |  qt! | t  j" j=  r|t> |  qt! | t  j" j?  rt@ |  qt! | t  j" jA  r| jB } qt! | t  j" jC  rd } qt! | t  j" jD  r	| d 7} tE |  qt! | t  j" jF  r.tG | d  qt! | t  j" jH  rtG | d  qqWd a' tI   tJ   x t  jK jL D] } |   qxWg      f d   } t   t   t d  t   tM    } | j   x | D] } | |  qW jN d jO tP |  tP |	  tP |    xE  D]= } x- tQ jR | d  D] } t | j d   q?Wt   q&Wx t  jK jS D] } |   qtWt   t  jK jT rt  jK jU d k rt d  t   n  t d  t d  t S(   s_   
    The master lint function, that's responsible for staging all of the
    other checks.
    t   descriptions:   Checks the script for errors and prints script statistics.t   require_commandR   t   nargst   ?t   actionR   t   helps   The file to write to.t   ws    lint report, generated at: s   utf-8i    i   t   definet   defaultc           s     |  } | j  d k r d  S|  d  k r2 d } n d j |   } | d j t | j   t | j  t | j  d | j | j  d | j | j   7}  j |  d  S(   Ni    s   The games   The {0} translations    contains {0} dialogue blocks, containing {1} words
and {2} characters, for an average of {3:.1f} words and {4:.0f}
characters per block. g      ?(   R   R)   RA   R   R   R   t   append(   t   languaget   countR   (   t   countst   lines(    s   renpy/lint.pyt   report_language6  s    
	s   Statistics:s9   The game contains {0} menus, {1} images, and {2} screens.iN   t   autos;   Remember to set config.developer to False before releasing.sH   Lint is not a substitute for thorough testing. Remember to update Ren'PysB   before releasing. New releases fix bugs and improve compatibility.N(V   R   t	   argumentst   ArgumentParserR*   t   add_argumentt
   parse_argsR   t   opent   syst   stdoutR   R   R;   R   t   codecst   BOM_UTF8R   t   versiont   timet   ctimeR	   R@   R$   R%   R&   R   t	   all_stmtsR   R   t   collectionst   defaultdictR   R)   RY   R   t   Showt   SceneRm   R   R   t   ImageR_   Rl   t   HideRp   t   WithRq   t   SayR   R   RL   t   MenuR   t   JumpR   t   CallR   t   WhileR   t   IfR   t   UserStatementRw   t   LabelR   t	   TranslateR   t   EndTranslatet   ScreenR   t   DefineR   t   DefaultR   R   Re   t
   lint_hooksR   R   RA   R   t   textwrapt   wrapt   lint_stats_callbackst	   developert   original_developer(   t   apR   R   R   R/   R	  R   t
   menu_countt   screen_countt   image_countt   _fnt   _lnR^   R   t	   languagesR   t   ll(    (   R   R   s   renpy/lint.pyR;     s    	*1
!


	


"



(;   t
   __future__R    t   renpy.displayR   t
   renpy.textR  R  R   R  R
  R  t   __builtin__R#   t   dirR   R   R)   R@   R   R   R   R   R   R   R"   R4   R7   R>   R   RF   RG   RO   R\   R_   Rb   Rl   Rm   Rp   Rq   Rw   R   R   R   R   R   R   R   R   R   R   R   R   R   R   R   t   objectR   R   R;   (    (    (    s   renpy/lint.pyt   <module>   sf   			,		-		4				
						+	*									"								