3 C\# @sdZddlmZddlmZmZddlmZmZddl m Z e dddd d d d d ddddg Z e ddddddgZ ejejejejejejdZGdddeZdS)z jinja2.parser ~~~~~~~~~~~~~ Implements the template parser. :copyright: (c) 2017 by the Jinja Team. :license: BSD, see LICENSE for more details. )nodes)TemplateSyntaxErrorTemplateAssertionError)describe_tokendescribe_token_expr)imapforifblockZextendsprintmacroincludefromimportsetwith autoescapeeqneltZlteqgtZgteq)addsubmuldivfloordivmodc@seZdZdZdiddZdefddZddZdjd d Zdkd d Z dld dZ dmddZ ddZ dnddZ ddZddZddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zdod7d8Zdpd9d:Zd;d<Z d=d>Z!d?d@Z"dAdBZ#dCdDZ$dEdFZ%dGdHZ&dIdJZ'dKdLZ(dqdMdNZ)dOdPZ*drdQdRZ+dSdTZ,dUdVZ-dWdXZ.dYdZZ/d[d\Z0d]d^Z1d_d`Z2dsdadbZ3dcddZ4dtdedfZ5dgdhZ6dS)uParserzThis is the central parsing class Jinja2 uses. It's passed to extensions and can be used to parse expressions or statements. NcCst||_|j|||||_||_||_d|_i|_x,|jD] }x|jD]}|j |j|<qFWq:Wd|_ g|_ g|_ dS)NFr) environment _tokenizestreamnamefilenameclosed extensionsZiter_extensionstagsparse_last_identifier _tag_stack_end_token_stack)selfrsourcer!r"state extensiontagr/e/private/var/folders/pf/wv4htv3x0qs2c2mp0dnn0kchsvlck3/T/pip-install-emcbgzcf/jinja2/jinja2/parser.py__init__%s zParser.__init__cCs(|dkr|jjj}||||j|jdS)zConvenience method that raises `exc` with the message, passed line number or last line number as well as the current name and filename. N)r currentlinenor!r")r*msgr3excr/r/r0fail4s z Parser.failcCsg}x|D]}|jtt|q W|r@djdd|d D}nd}|dkrTdg}n d|g}|r|dk r||kr|jd|n|jd||jr|jd |jd |jd j||dS) Nz or css|]}dt|VqdS)z'%s'N)r).0exprr/r/r0 Csz&Parser._fail_ut_eof..zUnexpected end of template.zEncountered unknown tag '%s'.z_You probably made a nesting mistake. Jinja is expecting this tag, but currently looking for %s.z-Jinja was looking for the following tags: %s.z4The innermost block that needs to be closed is '%s'. r<)extendrrjoinappendr(r6)r*r!Zend_token_stackr3expectedexprsZcurrently_lookingmessager/r/r0 _fail_ut_eof=s*   zParser._fail_ut_eofcCs|j||j|S)zCalled if the parser encounters an unknown tag. Tries to fail with a human readable error message that could help to identify the problem. )rCr))r*r!r3r/r/r0fail_unknown_tag\szParser.fail_unknown_tagcCs*t|j}|dk r|j||jd||S)z9Like fail_unknown_tag but for end of template situations.N)listr)r?rC)r* end_tokensr3stackr/r/r0fail_eofcs  zParser.fail_eofcCs,|jjjdkrdS|dk r(|jjj|SdS)zAre we at the end of a tuple? variable_end block_endrparenTNF)rIrJrK)r r2typetest_any)r*extra_end_rulesr/r/r0 is_tuple_endjs zParser.is_tuple_endcCs6|jd7_tjtj}tjj|d|j|d|S)zDReturn a new free identifier as :class:`~jinja2.nodes.InternalName`.r:zfi%d)r3)r'object__new__rZ InternalNameNoder1)r*r3rvr/r/r0free_identifierrs zParser.free_identifierc Cs|jj}|jdkr |jd|j|jj|jd}z|jtkrTt |d|jjjS|jdkrf|j S|jdkrx|j S|j j |j}|dk r||S|jjd}|j|j|jWd|r|jjXdS) zParse a single statement.r!ztag name expectedTZparse_callfilterNF)r r2rLr6r3r(r?value_statement_keywordsgetattrparse_call_blockparse_filter_blockr$getpoprD)r*tokenZpop_tagextr/r/r0parse_statementys(     zParser.parse_statementFcCsL|jjd|jjd|j|}|jjjdkr:|j||rHt|j|S)aRParse multiple statements into a list until one of the end tokens is reached. This is used to parse the body of statements as it also parses template data if appropriate. The parser checks first if the current token is a colon and skips it if there is one. Then it checks for the block end and parses until if one of the `end_tokens` is reached. Per default the active token in the stream at the end of the call is the matched end token. If this is not wanted `drop_needle` can be set to `True` and the end token is removed. colonrJeof)r skip_ifexpectsubparser2rLrHnext)r*rF drop_needleresultr/r/r0parse_statementss     zParser.parse_statementscCsft|jj}|jdd}|jjdr<|j}tj|||dS|jd}|j ddd}tj ||||dS) zParse an assign statement.T)with_namespaceassign)r3N name:endset)rg)rl) rfr r3parse_assign_targetrc parse_tuplerAssign parse_filterriZ AssignBlock)r*r3targetr8Z filter_nodebodyr/r/r0 parse_sets    zParser.parse_setc Cs|jjdj}|jdd}|jjd|jddd}d}|jjdrL|j}|jjd}|jd}t|jj d krxg}n|jdd d }t j |||||||dS)zParse a for loop.zname:forname:in)rNFname:recursive) with_condexprrNNzname:if name:endfor name:elseZendforT)rg)r3)rt)ru)rwrx)rw) r rdr3rmrnrcparse_expressionrirfrWrFor)r*r3rqitertest recursiverrelse_r/r/r0 parse_fors     zParser.parse_forcCstj|jjdjd}}x||jdd|_|jd |_g|_ g|_ t |j}|jdrxtj|jj jd}|j j |qn|jdr|jd dd |_ PqW|S) zParse an if construct.zname:if)r3F)rv name:elif name:else name:endifT)rg)rrr)r)rIfr rdr3rnr|rirrZelif_r~rfr2r?)r*noderhr^r/r/r0parse_ifs"     zParser.parse_ifcCstjt|jjd}g}g}xb|jjjdkr~|jjj}|rF|jjd|j}|j d|j ||jjd|j |j qW||_ ||_ |jd dd|_|S) N)r3rJcommaparamrk name:endwithT)rg)r)rWithrfr r3r2rLrdrmset_ctxr?rytargetsvaluesrirr)r*rrrr3rqr/r/r0 parse_withs"      zParser.parse_withcCsDtjt|jjd}tjd|jg|_|jddd|_ tj |gS)N)r3rname:endautoescapeT)rg)r) rZScopedEvalContextModifierrfr r3KeywordryoptionsrirrZScope)r*rr/r/r0parse_autoescapes  zParser.parse_autoescapecCsptjt|jjd}|jjdj|_|jjd|_ |jj j dkrJ|j d|j d dd|_|jjd |j|S) N)r3r!z name:scopedrzpBlock names in Jinja have to be valid Python identifiers and may not contain hyphens, use an underscore instead. name:endblockT)rgzname:)r)rZBlockrfr r3rdrWr!rcscopedr2rLr6rirr)r*rr/r/r0 parse_blocks zParser.parse_blockcCs"tjt|jjd}|j|_|S)N)r3)rZExtendsrfr r3rytemplate)r*rr/r/r0 parse_extendss zParser.parse_extendscCsH|jjjddr>|jjjdr>t|jjdk|_|jjn||_|S)Nz name:withz name:withoutz name:contextr) r r2rMlookr|rfrW with_contextskip)r*rdefaultr/r/r0parse_import_contexts  zParser.parse_import_contextcCsbtjt|jjd}|j|_|jjjdrP|jj jdrPd|_ |jj dnd|_ |j |dS)N)r3z name:ignorez name:missingTF) rIncluderfr r3ryrr2r|rZignore_missingrr)r*rr/r/r0 parse_includes zParser.parse_includecCsFtjt|jjd}|j|_|jjd|jddj |_ |j |dS)N)r3zname:asT) name_onlyF) rImportrfr r3ryrrdrmr!rqr)r*rr/r/r0 parse_import)s   zParser.parse_importcs tjtjjdj_jjdg_fdd}xjrRjjdjj j dkr|rhPj dd}|j j d rjd |jtd jjd rj dd}jj|j |j fnjj|j |sjj j dkrPq@jjdq@Wtd sd_S)N)r3z name:importcsBjjjdkr>jjjdr>tjjdk_jjdSdS)Nrwithoutz name:contextTF)rr)r r2rWrr|rfrrr/)rr*r/r0 parse_context6s  z(Parser.parse_from..parse_contextrr!T)r_z4names starting with an underline can not be imported)r5zname:asrF)rZ FromImportrfr r3ryrrdnamesr2rLrmr! startswithr6rrcr?hasattrr)r*rrqaliasr/)rr*r0 parse_from0s4        zParser.parse_fromcCsg|_}g|_}|jjdxl|jjjdkr|r@|jjd|jdd}|jd|jjdrr|j |j n|r|j d|j |q"W|jjddS) NlparenrKrT)rrrkz-non-default argument follows default argument) argsdefaultsr rdr2rLrmrrcr?ryr6)r*rrrargr/r/r0parse_signatureVs        zParser.parse_signaturecCsttjt|jjd}|jjjdkr.|j|n g|_g|_ |j |_ t |j tj s`|jd|j|jddd|_|S)N)r3rz expected call name:endcallT)rg)r)rZ CallBlockrfr r3r2rLrrrryrU isinstanceCallr6rirr)r*rr/r/r0rZfs  zParser.parse_call_blockcCs8tjt|jjd}|jddd|_|jddd|_|S)N)r3T) start_inlinename:endfilter)rg)r) rZ FilterBlockrfr r3rprVrirr)r*rr/r/r0r[ts  zParser.parse_filter_blockcCsBtjt|jjd}|jddj|_|j||jddd|_ |S)N)r3T)r name:endmacro)rg)r) rZMacrorfr r3rmr!rrirr)r*rr/r/r0 parse_macro{s   zParser.parse_macrocCsTtjt|jjd}g|_x4|jjjdkrN|jr<|jjd|jj|j qW|S)N)r3rJr) rOutputrfr r3r2rLrdr?ry)r*rr/r/r0 parse_prints zParser.parse_printTcCs|rN|jjjdkrN|jjd}t|j|jjd}tj|j|j|jd}nL|rt|jjd}tj |jd|jd}n&|r|j d|d}n|j }|j d|j s|jd|jjj|j|S)aParse an assignment target. As Jinja2 allows assignments to tuples, this function can parse all allowed assignment targets. Per default assignments to tuples are parsed, that can be disable however by setting `with_tuple` to `False`. If only assignments to names are wanted `name_only` can be set to `True`. The `extra_end_rules` parameter is forwarded to the tuple parsing function. If `with_namespace` is enabled, a namespace assignment may be parsed. dotr!)r3storeT) simplifiedrNzcan't assign to %r)r rrLrdrfrZNSRefrWr3Namern parse_primaryrZ can_assignr6 __class____name__lower)r*Z with_tuplerrNrjr^attrrqr/r/r0rms"       zParser.parse_assign_targetcCs|r |jS|jS)zParse an expression. Per default all expressions are parsed, if the optional `with_condexpr` parameter is set to `False` conditional expressions are not parsed. )parse_condexprparse_or)r*rvr/r/r0ryszParser.parse_expressioncCsf|jjj}|j}xN|jjdr`|j}|jjdr>|j}nd}tj||||d}|jjj}qW|S)Nzname:ifz name:else)r3)r r2r3rrcrrZCondExpr)r*r3Zexpr1Zexpr2Zexpr3r/r/r0rs   zParser.parse_condexprcCsJ|jjj}|j}x2|jjdrD|j}tj|||d}|jjj}qW|S)Nzname:or)r3)r r2r3 parse_andrcrOr)r*r3leftrightr/r/r0rs zParser.parse_orcCsJ|jjj}|j}x2|jjdrD|j}tj|||d}|jjj}qW|S)Nzname:and)r3)r r2r3 parse_notrcrAnd)r*r3rrr/r/r0rs zParser.parse_andcCs4|jjjdr,t|jj}tj|j|dS|jS)Nzname:not)r3) r r2r|rfr3rNotr parse_compare)r*r3r/r/r0rs zParser.parse_notcCs|jjj}|j}g}x|jjj}|tkrLt|j|jtj ||jnh|jj drp|jtj d|jnD|jjj dr|jj j dr|jj d|jtj d|jnP|jjj}qW|s|Stj|||dS)Nzname:ininzname:notrnotin)r3)r r2r3 parse_math1rL_compare_operatorsrfr?rZOperandrcr|rrCompare)r*r3r8ops token_typer/r/r0rs&     zParser.parse_comparecCsb|jjj}|j}xJ|jjjdkr\t|jjj}t|j|j}||||d}|jjj}qW|S)Nrr)r3)rr)r r2r3 parse_concatrL _math_nodesrf)r*r3rclsrr/r/r0rs  zParser.parse_math1cCsb|jjj}|jg}x*|jjjdkr>t|j|j|jqWt|dkrT|dStj ||dS)Ntilder:r)r3) r r2r3 parse_math2rLrfr?lenrZConcat)r*r3rr/r/r0rs    zParser.parse_concatcCsb|jjj}|j}xJ|jjjdkr\t|jjj}t|j|j}||||d}|jjj}qW|S)Nrrrr)r3)rrrr)r r2r3 parse_powrLrrf)r*r3rrrr/r/r0rs  zParser.parse_math2cCsV|jjj}|j}x>|jjjdkrPt|j|j}tj|||d}|jjj}qW|S)Npow)r3)r r2r3 parse_unaryrLrfrPow)r*r3rrr/r/r0rs  zParser.parse_powcCs|jjj}|jjj}|dkrrnrd parse_list parse_dictr6r)r*r^rbufr3r/r/r0r(s<                zParser.parse_primaryc sjjj}|rj}n|r"j}n fdd}g}d}xL|rHjjdj|rTP|j|jjjdkrtd}nPjjj}q8W|s|r|dS|sj dt jjt j |d|d S) aWorks like `parse_expression` but if multiple expressions are delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created. This method could also return a regular expression instead of a tuple if no commas where found. The default parsing mode is a full tuple. If `simplified` is `True` only names and literals are parsed. The `no_condexpr` parameter is forwarded to :meth:`parse_expression`. Because tuples do not require delimiters and may end in a bogus comma an extra hint is needed that marks the end of a tuple. For example for loops support tuples between `for` and `in`. In that case the `extra_end_rules` is set to ``['name:in']``. `explicit_parentheses` is true if the parsing was triggered by an expression in parentheses. This is used to figure out if an empty tuple is a valid expression or not. cs jddS)NF)rv)ryr/)r*r/r0dsz$Parser.parse_tuple..FrTrz Expected an expression, got '%s'r)r3) r r2r3rryrdrOr?rLr6rrTuple) r*rrvrNrr3r&rZis_tupler/)r*r0rnJs2     zParser.parse_tuplecCsn|jjd}g}x@|jjjdkrP|r0|jjd|jjjdkr@P|j|jqW|jjdtj||jdS)Nrrbracketr)r3) r rdr2rLr?ryrListr3)r*r^itemsr/r/r0rs   zParser.parse_listcCs|jjd}g}xf|jjjdkrv|r0|jjd|jjjdkr@P|j}|jjd|j}|jtj|||jdqW|jjdtj ||jdS)Nrrbracerra)r3) r rdr2rLryr?rZPairr3Dict)r*r^rkeyrWr/r/r0rs    zParser.parse_dictcCsFx@|jjj}|dks|dkr(|j|}q|dkr<|j|}qPqW|S)Nrrr)r r2rLparse_subscript parse_call)r*rrr/r/r0rs   zParser.parse_postfixcCs`xZ|jjj}|dkr |j|}q|dkrB|jjjdkrB|j|}q|dkrV|j|}qPqW|S)Npiper!isr)r r2rLrprW parse_testr)r*rrr/r/r0rs    zParser.parse_filter_exprcCs t|j}|jdkr|jj}t|j|jdkrFtj||jd|jdS|jdkr^|jd|jtj |j|jd}tj ||d|jdS|jdkrg}x0|jjjdkr|r|jj d |j |j qW|jj dt|d kr|d }ntj|d|jd}tj ||d|jdS|jd |jdS) Nrr!r)r3rzexpected name or numberrrrr:rzexpected subscript expression)rfr rLr2rZGetattrrWr3r6rZGetitemrdr?parse_subscribedrr)r*rr^Z attr_tokenrrr/r/r0rs.            zParser.parse_subscriptcCs|jjj}|jjjdkr*t|jdg}n*|j}|jjjdkrD|St|j|g}|jjjdkrn|jdn(|jjjdkr|j|jn |jd|jjjdkrt|j|jjjdkr|j|jq|jdn |jdtj|d|iS)Nrarrr3)rr)rr) r r2r3rLrfryr?rSlice)r*r3rrr/r/r0rs*        zParser.parse_subscribedc sjjdg}g}d}}d}fdd}x jjjdkrP|rbjjdjjjdkrbPjjjdkr||dko|dktjj}njjjdkr||dktjj}n||dko|dkjjjd kojjjd kr2jjj}jjd j} |j t j || | j d n|| |j jd }q2Wjjd|dkrt||||fSt j |||||j d S)NrFcs|sjdjdS)Nz+invalid syntax for function call expression)r6r3)r8)r*r^r/r0ensuresz!Parser.parse_call..ensurerKrrrr!rkr)r3T)r rdr2rLrfryrrWrr?rrr3r) r*rrkwargsdyn_args dyn_kwargsZ require_commarrrWr/)r*r^r0rsF              zParser.parse_callc Csx|jjjdks|r|s"t|j|jjd}|j}x2|jjjdkrft|j|d|jjdj7}q6W|jjjdkr|jd\}}}}ng}g}d}}tj|||||||j d}d}qW|S)Nrr!r.r)r3F) r r2rLrfrdrWrrFilterr3) r*rrr^r!rrrrr/r/r0rp s"    zParser.parse_filterc Cst|j}|jjjdr(t|jd}nd}|jjdj}x2|jjjdkrlt|j|d|jjdj7}q|jjXS) Ncs8r4dj}jtjdd|ddd=dS)Nr)r3)r3r?rr)r3)rr data_bufferr/r0 flush_data[s z#Parser.subparse..flush_datadata)r3Zvariable_beginT)rvrIZ block_beginrJzinternal parsing error)r?r)r r2rLrWrZ TemplateDatar3rfrnrdrMr`rrEr=AssertionErrorr])r*rFZadd_datarr^rSr/)rrrr0reSsD                 zParser.subparsecCs"tj|jdd}|j|j|S)z0Parse the whole template into a `Template` node.r:)r3)rTemplatereZset_environmentr)r*rhr/r/r0r&s z Parser.parse)NNN)N)NN)N)N)F)TFNF)T)T)FTNF)F)N)7r __module__ __qualname____doc__r1rr6rCrDrHrOrTr`rirsrrrrrrrrrrrrZr[rrrmryrrrrrrrrrrrrnrrrrrrrrprrer&r/r/r/r0r sl           &          " 6  /  0rN)r Zjinja2rZjinja2.exceptionsrrZ jinja2.lexerrrZjinja2._compatr frozensetrXrAddSubZMulDivFloorDivModrrPrr/r/r/r0 s