ó
•‰]c           @   sX   d  Z  d d l Z d e f d „  ƒ  YZ d e f d „  ƒ  YZ d e f d „  ƒ  YZ d S(	   sÇ   
This module contains a tokenizer for Excel formulae.

The tokenizer is based on the Javascript tokenizer found at
http://ewbi.blogs.com/develops/2004/12/excel_formula_p.html written by Eric
Bachtal
iÿÿÿÿNt   TokenizerErrorc           B   s   e  Z d  Z RS(   s$   Base class for all Tokenizer errors.(   t   __name__t
   __module__t   __doc__(    (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR       s   t	   Tokenizerc           B   sß   e  Z d  Z e j d ƒ Z e j d ƒ Z i e j d ƒ d 6e j d ƒ d 6Z 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 d „ Z d „  Z d „  Z RS(    sf  
    A tokenizer for Excel worksheet formulae.

    Converts a unicode string representing an Excel formula (in A1 notation)
    into a sequence of `Token` objects.

    `formula`: The unicode string to tokenize

    Tokenizer defines a method `._parse()` to parse the formula into tokens,
    which can then be accessed through the `.items` attribute.

    s   ^[1-9](\.[0-9]+)?[Ee]$s   [ \n]+s   "(?:[^"]*"")*[^"]*"(?!")t   "s   '(?:[^']*'')*[^']*'(?!')t   's   #NULL!s   #DIV/0!s   #VALUE!s   #REF!s   #NAME?s   #NUM!s   #N/As   #GETTING_DATAs   ,;}) +-*/^&=><%c         C   s;   | |  _  g  |  _ g  |  _ d |  _ g  |  _ |  j ƒ  d  S(   Ni    (   t   formulat   itemst   token_stackt   offsett   tokent   _parse(   t   selfR   (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyt   __init__.   s    					c      
   C   s¹  |  j  r d S|  j s d S|  j d d k r? |  j  d 7_  n# |  j j t |  j t j ƒ ƒ d Sd |  j f d |  j f d |  j f d |  j	 f d	 |  j	 f d
 |  j
 f d |  j f d |  j f d |  j f f	 } i  } x- | D]% \ } } | j t j | | ƒ ƒ qá Wxž |  j  t |  j ƒ k  rª|  j ƒ  r7qn  |  j |  j  } | |  j k rc|  j ƒ  n  | | k rˆ|  j  | | ƒ  7_  q|  j j | ƒ |  j  d 7_  qW|  j ƒ  d S(   s5   Populate self.items with the tokens from the formula.Ni    t   =i   s   "'t   [t   #t    s   
s
   +-*/^&=><%s   {(s   )}s   ;,(   R
   R   R   t   appendt   Tokent   LITERALt   _parse_stringt   _parse_bracketst   _parse_errort   _parse_whitespacet   _parse_operatort   _parse_openert   _parse_closert   _parse_separatort   updatet   dictt   fromkeyst   lent   check_scientific_notationt   TOKEN_ENDERSt
   save_tokenR   (   R   t	   consumerst
   dispatchert   charst   consumert	   curr_char(    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR   7   s>    		c         C   sé   |  j  d d ƒ |  j |  j } | d	 k s2 t ‚ |  j | } | j |  j |  j ƒ } | d
 k r˜ | d k rv d n d } t d | |  j f ƒ ‚ n  | j d ƒ } | d k rÏ |  j	 j
 t j | ƒ ƒ n |  j j
 | ƒ t | ƒ S(   s¹  
        Parse a "-delimited string or '-delimited link.

        The offset must be pointing to either a single quote ("'") or double
        quote ('"') character. The strings are parsed according to Excel
        rules where to escape the delimiter you just double it up. E.g.,
        "abc""def" in Excel is parsed as 'abc"def' in Python.

        Returns the number of characters matched. (Does not update
        self.offset)

        t
   can_followt   :R   R   t   stringt   links-   Reached end of formula while parsing %s in %si    (   R   R   N(   t   assert_empty_tokenR   R
   t   AssertionErrort   STRING_REGEXESt   matcht   NoneR    t   groupR   R   R   t   make_operandR   R!   (   R   t   delimt   regexR1   t   subtype(    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR   _   s    c         C   s  |  j  |  j d k s t ‚ g  t j d |  j  |  j ƒ D] } | j ƒ  d f ^ q9 } g  t j d |  j  |  j ƒ D] } | j ƒ  d f ^ qt } d } xf t | | ƒ D]T \ } } | | 7} | d k r© | d } |  j j |  j  |  j |  j | !ƒ | Sq© Wt	 d |  j  ƒ ‚ d S(	   sœ   
        Consume all the text between square brackets [].

        Returns the number of characters matched. (Does not update
        self.offset)

        R   s   \[i   s   \]iÿÿÿÿi    s   Encountered unmatched '[' in %sN(
   R   R
   R/   t   ret   finditert   startt   sortedR   R   R    (   R   t   tt   leftst   rightst
   open_countt   idxt
   open_closet   outer_right(    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR   }   s    88

	c         C   s¹   |  j  d d ƒ |  j |  j d k s, t ‚ |  j |  j } xZ |  j D]O } | j | ƒ rF |  j j t j	 d j
 |  j ƒ | ƒ ƒ |  j 2t | ƒ SqF Wt d |  j |  j f ƒ ‚ d S(   sÃ   
        Consume the text following a '#' as an error.

        Looks for a match in self.ERROR_CODES and returns the number of
        characters matched. (Does not update self.offset)

        R*   t   !R   t    s)   Invalid error code at position %d in '%s'N(   R.   R   R
   R/   t   ERROR_CODESt
   startswithR   R   R   R4   t   joinR   R!   R    (   R   t
   subformulat   err(    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR   –   s    )c         C   sb   |  j  |  j d k s t ‚ |  j j t |  j  |  j t j ƒ ƒ |  j j |  j  |  j ƒ j	 ƒ  S(   s†   
        Consume a string of consecutive spaces.

        Returns the number of spaces found. (Does not update self.offset).

        R   s   
(   R   s   
(
   R   R
   R/   R   R   R   t   WSPACEt	   WSPACE_RER1   t   end(   R   (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR   ª   s    &c         C   su  |  j  |  j |  j d !d
 k rT |  j j t |  j  |  j |  j d !t j ƒ ƒ d S|  j  |  j } | d k sv t ‚ | d k r— t d t j ƒ } nÊ | d k r¸ t | t j ƒ } n© |  j sÖ t | t j ƒ } n‹ t	 d „  t
 |  j ƒ Dƒ d ƒ } | o1| j t j k p1| j t j k p1| j t j k } | rOt | t j ƒ } n t | t j ƒ } |  j j | ƒ d	 S(   s   
        Consume the characters constituting an operator.

        Returns the number of characters consumed. (Does not update
        self.offset)

        i   s   >=s   <=s   <>s
   %*/^&=><+-t   %s   */^&=><c         s   s'   |  ] } | j  t j k r | Vq d  S(   N(   t   typeR   RJ   (   t   .0t   i(    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pys	   <genexpr>Í   s    i   (   s   >=s   <=s   <>N(   R   R
   R   R   R   t   OP_INR/   t   OP_POSTt   OP_PREt   nextt   reversedR2   R7   t   CLOSERN   t   OPERAND(   R   R)   R   t   prevt   is_infix(    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR   µ   s0     		c         C   s¹   |  j  |  j d k s t ‚ |  j  |  j d k rN |  j ƒ  t j d ƒ } nG |  j r† d j |  j ƒ d } |  j 2t j | ƒ } n t j d ƒ } |  j j	 | ƒ |  j
 j	 | ƒ d S(   s‰   
        Consumes a ( or { character.

        Returns the number of characters consumed. (Does not update
        self.offset)

        t   (t   {RD   i   (   RZ   R[   (   R   R
   R/   R.   R   t   make_subexpR   RG   R   R   R	   (   R   R   t   token_value(    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR   Û   s    
	c         C   st   |  j  |  j d k s t ‚ |  j j ƒ  j ƒ  } | j |  j  |  j k r` t d |  j  ƒ ‚ n  |  j j	 | ƒ d S(   s‰   
        Consumes a } or ) character.

        Returns the number of characters consumed. (Does not update
        self.offset)

        t   )t   }s   Mismatched ( and { pair in '%s'i   (   R^   R_   (
   R   R
   R/   R	   t   popt
   get_closert   valueR    R   R   (   R   R   (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR   ñ   s    c         C   sÁ   |  j  |  j } | d k s" t ‚ | d k r@ t j d ƒ } nm y |  j d j } Wn# t k
 ry t d t j ƒ } n4 X| t j	 k rž t d t j ƒ } n t j d ƒ } |  j
 j | ƒ d S(   s‰   
        Consumes a ; or , character.

        Returns the number of characters consumed. (Does not update
        self.offset)

        t   ;t   ,iÿÿÿÿi   (   Rc   Rd   (   R   R
   R/   R   t   make_separatorR	   RN   t
   IndexErrorRQ   t   PARENR   R   (   R   R)   R   t   top_type(    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR     s    c         C   sv   |  j  |  j } | d k rr t |  j ƒ d k rr |  j j d j |  j ƒ ƒ rr |  j j | ƒ |  j d 7_ t St	 S(   s¾   
        Consumes a + or - character if part of a number in sci. notation.

        Returns True if the character was consumed and self.offset was
        updated, False otherwise.

        s   +-i   RD   (
   R   R
   R!   R   t   SN_RER1   RG   R   t   Truet   False(   R   R)   (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR"     s    c         C   s?   |  j  r; |  j  d | k r; t d |  j |  j f ƒ ‚ n  d S(   s:  
        Ensure that there's no token currently being parsed.

        Or if there is a token being parsed, it must end with a character in
        can_follow.

        If there are unconsumed token contents, it means we hit an unexpected
        token transition. In this case, we raise a TokenizerError

        iÿÿÿÿs+   Unexpected character at position %d in '%s'N(   R   R    R
   R   (   R   R*   (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR.   +  s    c         C   s<   |  j  r8 |  j j t j d j |  j  ƒ ƒ ƒ |  j  2n  d S(   s9   If there's a token being parsed, add it to the item list.RD   N(   R   R   R   R   R4   RG   (   R   (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR$   ;  s    	%c         C   sR   |  j  s d S|  j  d j t j k r4 |  j  d j Sd d j d „  |  j  Dƒ ƒ S(   s+   Convert the parsed tokens back to a string.RD   i    R   c         s   s   |  ] } | j  Vq d  S(   N(   Rb   (   RO   R   (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pys	   <genexpr>G  s    (   R   RN   R   R   Rb   RG   (   R   (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyt   renderA  s
    	(   s   #NULL!s   #DIV/0!s   #VALUE!s   #REF!s   #NAME?s   #NUM!s   #N/As   #GETTING_DATA(    (   R   R   R   R8   t   compileRi   RK   R0   RE   R#   R   R   R   R   R   R   R   R   R   R   R"   R.   R$   Rl   (    (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR      s.    			(					&					R   c           B   sÝ   e  Z d  Z d d d g Z d Z d Z d Z d Z d Z d	 Z	 d
 Z
 d Z d Z d Z d d „ Z d Z d Z d Z d Z d Z d „  Z e d „  ƒ Z d Z d Z e e d „ ƒ Z d „  Z d Z d Z e d „  ƒ Z RS(   s)  
    A token in an Excel formula.

    Tokens have three attributes:

    * `value`: The string value parsed that led to this token
    * `type`: A string identifying the type of token
    * `subtype`: A string identifying subtype of the token (optional, and
                 defaults to "")

    Rb   RN   R7   R   RW   t   FUNCt   ARRAYRg   t   SEPs   OPERATOR-PREFIXs   OPERATOR-INFIXs   OPERATOR-POSTFIXs   WHITE-SPACERD   c         C   s   | |  _  | |  _ | |  _ d  S(   N(   Rb   RN   R7   (   R   Rb   t   type_R7   (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR   e  s    		t   TEXTt   NUMBERt   LOGICALt   ERRORt   RANGEc         C   s   d j  |  j |  j |  j ƒ S(   Nu   {0} {1} {2}:(   t   formatRN   R7   Rb   (   R   (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyt   __repr__w  s    c         C   s•   | j  d ƒ r |  j } ng | j  d ƒ r6 |  j } nL | d k rN |  j } n4 y t | ƒ |  j } Wn t k
 r |  j } n X|  | |  j | ƒ S(   s   Create an operand token.R   R   t   TRUEt   FALSE(   Ry   Rz   (	   RF   Rr   Ru   Rt   t   floatRs   t
   ValueErrorRv   RW   (   t   clsRb   R7   (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR4   z  s    
t   OPENRV   c         C   s§   | d d
 k s t  ‚ | r@ t j d | ƒ s4 t  ‚ t j } n9 | d k rX t j } n! | d k rp t j } n	 t j } | d	 k rŽ |  j n |  j } |  | | | ƒ S(   s•   
        Create a subexpression token.

        `value`: The value of the token
        `func`: If True, force the token to be of type FUNC

        iÿÿÿÿR[   R_   RZ   R^   s   .+\(|\)s   {}s   ()s   )}(   R[   R_   RZ   R^   (	   R/   R8   R1   R   Rn   Ro   Rg   RV   R~   (   R}   Rb   t   funcRq   R7   (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR\   —  s    		c         C   s|   |  j  |  j |  j |  j f k s' t ‚ |  j |  j k s? t ‚ |  j  |  j k rW d n d } |  j | d |  j  |  j k ƒS(   s6   Return a closing token that matches this token's type.R_   R^   R   (   RN   Rn   Ro   Rg   R/   R7   R~   R\   (   R   Rb   (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyRa   ­  s    't   ARGt   ROWc         C   sC   | d k s t  ‚ | d k r' |  j n |  j } |  | |  j | ƒ S(   s   Create a separator tokenRd   Rc   (   Rd   Rc   (   R/   R€   R   Rp   (   R}   Rb   R7   (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyRe   ¿  s    (   R   R   R   t	   __slots__R   RW   Rn   Ro   Rg   Rp   RS   RQ   RR   RJ   R   Rr   Rs   Rt   Ru   Rv   Rx   t   classmethodR4   R~   RV   Rk   R\   Ra   R€   R   Re   (    (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyR   J  s8   		(   R   R8   t	   ExceptionR    t   objectR   R   (    (    (    s9   lib/python2.7/site-packages/openpyxl/formula/tokenizer.pyt   <module>   s
   ÿ ;