"Vfi:bdZddlZGddeZGddZGddZdS) z 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 NceZdZdZdS)TokenizerErrorz$Base class for all Tokenizer errors.N)__name__ __module__ __qualname____doc__Ic:\PYTHON\DbComparer\venv\Lib\site-packages\openpyxl/formula/tokenizer.pyrr s....r rceZdZdZejdZejdZejdejddZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZddZdZdZdS) Tokenizera^ A tokenizer for Excel worksheet formulae. Converts a str string representing an Excel formula (in A1 notation) into a sequence of `Token` objects. `formula`: The str string to tokenize Tokenizer defines a method `._parse()` to parse the formula into tokens, which can then be accessed through the `.items` attribute. z^[1-9](\.[0-9]+)?[Ee]$z[ \n]+z"(?:[^"]*"")*[^"]*"(?!")z'(?:[^']*'')*[^']*'(?!')"')z#NULL!z#DIV/0!z#VALUE!z#REF!z#NAME?z#NUM!z#N/Az #GETTING_DATAz,;}) +-*/^&=><%ct||_g|_g|_d|_g|_|dS)Nr)formulaitems token_stackoffsettoken_parse)selfrs r __init__zTokenizer.__init__.s7     r c |jrdS|jsdS|jddkr|xjdz c_n9|jt |jtjdSd|jfd|jfd|jfd|j fd |j fd |j fd |j fd |j fd |j ff }i}|D]3\}}|t||4|jt#|jkr|r2|j|j}||jvr|||vr|xj||z c_n*|j||xjdz c_|jt#|jk|dS)z5Populate self.items with the tokens from the formula.Nr=z"'[#  z +-*/^&=><%z{()}z;,)rrrappendTokenLITERAL _parse_string_parse_brackets _parse_error_parse_whitespace_parse_operator _parse_opener _parse_closer_parse_separatorupdatedictfromkeyslencheck_scientific_notation TOKEN_ENDERS save_tokenr)r consumers dispatchercharsconsumer curr_chars r rzTokenizer._parse7s ;  F|  F \!_ # # KK1 KKK J  eDL%-@@ A A A F D& ' $& ' $# $ $( ) 4) * 4/ 0 4% & 4% & 4( )   ( > >OE8   dmmE8<< = = = =kC ------//  T[1ID---!!!J&& 4z)4666  !!),,, q kC ---- r c|d|j|j}|dvsJ|j|}||j|jd}|$|dkrdnd}t d|d |j|d }|dkr3|jt |n|j |t|S) a 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) : can_followrNrstringlinkz%Reached end of formula while parsing z in r) assert_empty_tokenrrSTRING_REGEXESmatchrgrouprr"r# make_operandrr0)rdelimregexrAsubtypes r r%zTokenizer._parse_string_s 3/// T[) """"#E* DL677 ="'3,,hhFG !d!d!dVZVb!d!dee e A C<< J  e0077 8 8 8 8 J  e $ $ $5zzr c|j|jdksJdtjd|j|jdD}dtjd|j|jdD}d}t ||zD]M\}}||z }|dkr=|dz}|j|j|j|j|z|cSNtd |j) z Consume all the text between square brackets []. Returns the number of characters matched. (Does not update self.offset) rc:g|]}|dfS)rstart.0ts r z-Tokenizer._parse_brackets..s6AAAA!''))QAAAr z\[Nc:g|]}|dfS)rIrKs r rNz-Tokenizer._parse_brackets..s6BBBa17799b/BBBr z\]rrzEncountered unmatched '[' in )rrrefinditersortedrr"r)rleftsrights open_countidx open_close outer_rights r r&zTokenizer._parse_brackets{s9|DK(C////AAUDL$>??AAABB+eT\$+,,%?@@BBB %efn55 # #OC * $JQ!Ag  !!LT[;-F!FGIII""""  KT\KKLLLr c|d|j|jdksJ|j|jd}|jD]}||rh|jtd |j |z|j dd=t|cStd|jd|jd) z 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;rNzInvalid error code at position  in 'r) r?rr ERROR_CODES startswithrr"r#rCjoinrr0r)r subformulaerrs r r'zTokenizer._parse_errors 3///|DK(C////\$+,,/ #  C$$S))  !!%"4"4RWWTZ5H5H35N"O"OPPPJqqqM3xx `t{``QUQ]```aaar c.|j|jdvsJ|jt |j|jtj|j|j|jdS)z Consume a string of consecutive spaces. Returns the number of spaces found. (Does not update self.offset). )rr N) rrrr"r#WSPACE WSPACE_RErAendrs r r(zTokenizer._parse_whitespacesx|DK(K7777 % T[ 95<HHIII~##DL$>??CCEEEr cN|j|j|jdzdvrN|jt |j|j|jdztjdS|j|j}|dvsJ|dkrt dtj}n|dvrt |tj}n|jst |tj}ntdt|jDd}|o>|j tj kp)|j tjkp|j tj k}|rt |tj}nt |tj}|j|dS) z Consume the characters constituting an operator. Returns the number of characters consumed. (Does not update self.offset) )z>=z<=z<>z %*/^&=><+-%z*/^&=>z,Tokenizer._parse_operator..s<44qFel22222244r Nr)rrrr"r#OP_INOP_POSTOP_PREnextreversedrFCLOSErmOPERAND)rr8rprevis_infixs r r)zTokenizer._parse_operators < DK!O3 48J J J J  e T[q89    1L- L((((   #u}--EE ) # #)U[11EE 7)U\22EE44HTZ$8$844459;;D  +.9 -.9 -   7i55i66 %   qr c|j|jdvsJ|j|jdkr/|td}nc|jrBd|jdz}|jdd=t|}ntd}|j||j |dS)z Consumes a ( or { character. Returns the number of characters consumed. (Does not update self.offset) )({r{r\rzNr) rrr?r# make_subexprr`rr"r)rr token_values r r*zTokenizer._parse_openers|DK(J6666 < $ + +  # # % % %%%c**EE Z +''$*--3K 111 %%k22EE%%c**E %    &&&qr c |j|jdvsJ|j}|j|j|jkrt d|jz|j|dS)z Consumes a } or ) character. Returns the number of characters consumed. (Does not update self.offset) ))}zMismatched ( and { pair in '%s'r) rrrpop get_closervaluerrr")rrs r r+zTokenizer._parse_closers|DK(J6666 $$&&1133 ;$,t{3 3 3 1DL@BB B %   qr c|j|j}|dvsJ|dkrtd}n |jdj}|tjkrtdtj}nEtd}n*#t$rtdtj}YnwxYw|j |dS)z Consumes a ; or , character. Returns the number of characters consumed. (Does not update self.offset) );,rrPrr) rrr#make_separatorrrmPARENrp IndexErrorrr")rr8rtop_types r r,zTokenizer._parse_separatorsL- J&&&&   ((--EE 6+B/4u{**!#u{33EE!0055EE  0 0 0c5;// 0 %   qsB$B:9B:c|j|j}|dvrvt|jdkr^|jd|jr,|j||xjdz c_dSdS)z 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. z+-rr\TF)rrr0rSN_RErAr`r")rr8s r r1z#Tokenizer.check_scientific_notationsL-    OOq((J$$RWWTZ%8%899) J  i ( ( ( KK1 KK4ur r cv|jr/|jd|vr"td|jd|jddSdS)a: 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 rPz!Unexpected character at position r]rN)rrrr)rr<s r r?zTokenizer.assert_empty_token'sY : h$*R. :: !fT[!f!fW[Wc!f!f!fgg g h h::r c|jrV|jtd|j|jdd=dSdS)z9If there's a token being parsed, add it to the item list.r\N)rrr"r#rCr`rgs r r3zTokenizer.save_token5sY :  J  e001D1DEE F F F 111   r c|jsdS|jdjtjkr|jdjSddd|jDzS)z+Convert the parsed tokens back to a string.r\rrc3$K|] }|jV dSrl)r)rLrs r roz#Tokenizer.render..As$AAUU[AAAAAAr )rrmr#r$rr`rgs r renderzTokenizer.render;s^z '2 Z] 5= 0 0:a=& &RWWAAdjAAAAAAAr N)r )rrrrrQcompilerrer@r^r2rrr%r&r'r(r)r*r+r,r1r?r3rr r r r r sh   BJ0 1 1E 9%%I RZ2 3 3 RZ2 3 3 N5K$L&&&P8MMM2bbb$ F F F$$$L, 2" h h h h BBBBBr r ceZdZdZgdZdZdZdZdZdZ dZ d Z d Z d Z d ZddZdZdZdZdZdZdZedZdZdZed dZdZdZdZedZdS)!r#a) 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 "") rrmrFr$rvFUNCARRAYrSEPzOPERATOR-PREFIXzOPERATOR-INFIXzOPERATOR-POSTFIXz WHITE-SPACEr\c0||_||_||_dSrlr)rrtype_rFs r rzToken.__init___s   r TEXTNUMBERLOGICALERRORRANGEcNd|j|j|jS)Nz {0} {1} {2}:)formatrmrFrrgs r __repr__zToken.__repr__qs %%ditzJJJr c|dr|j}nX|dr|j}n;|dvr|j}n/ t ||j}n#t $r |j}YnwxYw|||j|S)zCreate an operand token.rr)TRUEFALSE) r_rrrfloatr ValueErrorrrvclsrrFs r rCzToken.make_operandts   C $hGG   c " " $iGG ' ' 'kGG $e * $ $ $) $s5#+w///sAA32A3OPENruFc|ddvsJ|r$tjd|sJtj}n.|dvr tj}n|dvr tj}n tj}|dvr|jn|j}||||S)z Create a subexpression token. `value`: The value of the token `func`: If True, force the token to be of type FUNC rP)r{rrzrz.+\(|\)z{}z()r!)rQrAr#rrrrur)rrfuncrrFs r r|zToken.make_subexpsRy00000  8K// / //JEE d]]KEE d]]KEEJE$}}#))#(s5%)))r c|j|j|j|jfvsJ|j|jksJ|j|jkrdnd}|||j|jkS)z6Return a closing token that matches this token's type.rr)r)rmrrrrFrr|)rrs r rzToken.get_closerspyTY DJ?????|ty((((yDJ..CDI,BCCCr ARGROWcZ|dvsJ|dkr|jn|j}|||j|S)zCreate a separator token)rrr)rrrrs r rzToken.make_separators@ """""c\\#''sws5#'7+++r N)r\)F)rrrr __slots__r$rvrrrrrrrprqrdrrrrrrr classmethodrCrrur|rrrrr r r r#r#Ds  -,,IGG D E E C F E G F D FG E EKKK00[02 D E***[**DDD C C,,[,,,r r#)rrQ Exceptionrr r#r r r rs /////Y///qBqBqBqBqBqBqBqBh z,z,z,z,z,z,z,z,z,z,r