
     Ti&              	      "   % S r SSKJr  SSKJr  SSKrS/r\R                  \R                  \R                  \R                  \R                  \R                  \R                  \R                  S.rS\S'    " S	 S
5      r " S S5      rSS jrg)zSafe expression parser for symbolic dimension expressions.

This module provides a safe recursive descent parser for parsing symbolic
dimension expressions without using eval().
    )annotations)CallableNparse_symbolic_expression)maxMaxminMinfloorsqrtmodModz$dict[str, Callable[..., sympy.Expr]]_ALLOWED_FUNCTIONSc                  @    \ rS rSrSrS	S jrS
S jrSS jrSS jrSr	g)_ExpressionTokenizer    zbTokenizer for symbolic dimension expressions.

This is a safe tokenizer that does not use eval().
c                >    Xl         SU l        [        U5      U l        g )Nr   )textposlenlengthselfr   s     W/var/www/html/ai-image-ml/venv/lib/python3.13/site-packages/onnx_ir/_symbolic_shapes.py__init___ExpressionTokenizer.__init__&   s    	$i    c                    U R                  5         U R                  U R                  :  a  gU R                  U R                     $ )z3Peek at the current character without consuming it.N)_skip_whitespacer   r   r   r   s    r   peek_ExpressionTokenizer.peek+   s4    88t{{"yy""r   c                P   U R                   U R                  :  a  U R                  U R                      R                  5       (       a_  U =R                   S-  sl         U R                   U R                  :  a/  U R                  U R                      R                  5       (       a  M]  gggg)zSkip whitespace characters.   N)r   r   r   isspacer   s    r   r   %_ExpressionTokenizer._skip_whitespace2   sp    hh$488)<)D)D)F)FHHMH hh$488)<)D)D)F)F$)F$r   c           	        U R                  5         U R                  U R                  :  a  gU R                  U R                     nUR	                  5       (       a  U R                  nU R                  U R                  :  a  U R                  U R                     R	                  5       (       a]  U =R                  S-  sl        U R                  U R                  :  a.  U R                  U R                     R	                  5       (       a  M]  S[        U R                  X R                   5      4$ UR                  5       (       d  US:X  Ga  U R                  nU R                  U R                  :  a  U R                  U R                     R                  5       (       d  U R                  U R                     S;   a|  U =R                  S-  sl        U R                  U R                  :  aM  U R                  U R                     R                  5       (       a  M]  U R                  U R                     S;   a  M|  SU R                  X R                   4$ U R                  S-   U R                  :  aE  U R                  U R                  U R                  S-    nUS;   a  U =R                  S-  sl        S	U4$ US
;   a  U =R                  S-  sl        S	U4$ US:X  a  U =R                  S-  sl        gUS:X  a  U =R                  S-  sl        gUS:X  a  U =R                  S-  sl        g[        SU SU R                   SU R                   S35      e)zGet the next token.

Returns:
    A tuple of (token_type, token_value) or None if end of input.
    Token types: 'NUMBER', 'IDENT', 'OP', 'LPAREN', 'RPAREN', 'COMMA'
Nr#   NUMBER_z_.IDENT   )//**OPz+-*/%()LPARENr.   ))RPARENr0   ,)COMMAr2   zUnexpected character 'z' at position  in expression '')	r   r   r   r   isdigitintisalphaisalnum
ValueError)r   charstarttwo_chars       r   	get_token_ExpressionTokenizer.get_token7   s|    	88t{{"yy" <<>>HHE((T[[(TYYtxx-@-H-H-J-JA ((T[[(TYYtxx-@-H-H-J-Jc$))EHH"=>?? <<>>TS[HHE((T[[(		$((#++--4881D1LA ((T[[(		$((#++--4881D1L TYYuxx899 88a<$++%yyDHHqL9H<'Ah'' 7?HHMH$<3;HHMH"3;HHMH"3;HHMH!$TF.
BRSWS\S\R]]^_
 	
r   )r   r   r   Nr   strreturnNone)rB   z
str | NonerB   rC   )rB   ztuple[str, str | int] | None)
__name__
__module____qualname____firstlineno____doc__r   r    r   r>   __static_attributes__ r   r   r   r       s    
 
#
4
r   r   c                  |    \ rS rSrSrSS jrSS jrSS jrSS jrSS jr	SS jr
SS	 jrSS
 jrSS jrSS jrSrg)_ExpressionParsern   a*  Safe recursive descent parser for symbolic dimension expressions.

Supports:
    - Basic arithmetic: +, -, *, /, //, %, **
    - Functions: max(), min(), floor(), sqrt()
    - Symbolic variables (identifiers)
    - Integer literals
    - Parentheses for grouping

Grammar:
    expr       -> term (('+' | '-') term)*
    term       -> power (('*' | '/' | '//' | '%') power)*
    power      -> unary ('**' power)?
    unary      -> '-' unary | primary
    primary    -> NUMBER | IDENT | IDENT '(' args ')' | '(' expr ')'
    args       -> expr (',' expr)*
c                ^    [        U5      U l        Xl        S U l        U R	                  5         g )N)r   	tokenizerr   current_token_advancer   s     r   r   _ExpressionParser.__init__   s$    -d3	;?r   c                B    U R                   R                  5       U l        g)zAdvance to the next token.N)rP   r>   rQ   r   s    r   rR   _ExpressionParser._advance   s    !^^557r   c           	         U R                   b  U R                   S   U:w  a)  [        SU SU R                    SU R                   S35      eU R                   S   nU R                  5         U$ )z,Expect a specific token type and consume it.r   z	Expected z	 but got r4   r5   r#   )rQ   r:   r   rR   )r   
token_typevalues      r   _expect_ExpressionParser._expect   sv    %););A)>*)LJ<y1C1C0DDTUYU^U^T__`a  ""1%r   c                    U R                  5       nU R                  b&  [        SU R                   SU R                   S35      eU$ )z3Parse the expression and return a SymPy expression.Unexpected token z at end of expression 'r5   )_parse_exprrQ   r:   r   )r   results     r   parse_ExpressionParser.parse   sO    !!#)#D$6$6#77NtyykYZ[  r   c                r   U R                  5       nU R                  b  U R                  S   S:X  a  U R                  S   S;   as  U R                  S   nU R                  5         U R                  5       nUS:X  a  X-   nOX-
  nU R                  b(  U R                  S   S:X  a  U R                  S   S;   a  Ms  U$ )z&Parse an expression (handles + and -).r   r-   r#   )+-rb   )_parse_termrQ   rR   r   leftoprights       r   r]   _ExpressionParser._parse_expr   s    ! *""1%-""1%3##A&BMMO$$&ESy|| *""1%-""1%3 r   c                   U R                  5       nU R                  b  U R                  S   S:X  a  U R                  S   S;   a  U R                  S   nU R                  5         U R                  5       nUS:X  a  X-  nO@US:X  a  X-  nO5US:X  a  [        R                  " X-  5      nO[        R
                  " X5      nU R                  b(  U R                  S   S:X  a  U R                  S   S;   a  M  U$ )z#Parse a term (handles *, /, //, %).r   r-   r#   >   %*/r+   rl   rm   r+   )_parse_powerrQ   rR   sympyr
   r   re   s       r   rd   _ExpressionParser._parse_term   s      " *""1%-""1%)>>##A&BMMO%%'ESy|s|t{{4<0yy- *""1%-""1%)>> r   c                    U R                  5       nU R                  bJ  U R                  S   S:X  a7  U R                  S   S:X  a$  U R                  5         U R                  5       nX-  $ U$ )z&Parse a power expression (handles **).r   r-   r#   r,   )_parse_unaryrQ   rR   rn   )r   baseexponents      r   rn   _ExpressionParser._parse_power   sh      " *""1%-""1%-MMO((*H>!r   c                    U R                   bG  U R                   S   S:X  a4  U R                   S   S:X  a!  U R                  5         U R                  5       * $ U R                  5       $ )z+Parse a unary expression (handles unary -).r   r-   r#   rc   )rQ   rR   rr   _parse_primaryr   s    r   rr   _ExpressionParser._parse_unary   s`     *""1%-""1%,MMO%%'''""$$r   c                l   U R                   c  [        SU R                   S35      eU R                   u  pUS:X  a&  U R                  5         [        R
                  " U5      $ US:X  ap  Un[        U[        5      (       d   eU R                  5         U R                   b$  U R                   S   S:X  a  U R                  U5      $ [        R                  " USSS9$ US:X  a3  U R                  5         U R                  5       nU R                  S	5        U$ [        S
U R                    SU R                   S35      e)z\Parse a primary expression (number, identifier, function call, or parenthesized expression).zUnexpected end of expression 'r5   r'   r)   r   r/   Tintegerpositiver1   r\   r4   )rQ   r:   r   rR   ro   Integer
isinstancerA   _parse_function_callSymbolr]   rY   )r   rW   token_valuenameexprs        r   rw    _ExpressionParser._parse_primary   s&   %=dii[JKK"&"4"4
 !MMO==--  DdC((((MMO !!-$2D2DQ2G82S0066 <<dTBB !MMO##%DLL"K,T-?-?,@@PQUQZQZP[[\]^^r   c                j   U[         ;  aH  [        SU SU R                   SSR                  [	        [         R                  5       5      5       35      eU R                  S5        / nU R                  b  U R                  S   S:w  a  UR                  U R                  5       5        U R                  bd  U R                  S   S:X  aQ  U R                  5         UR                  U R                  5       5        U R                  b  U R                  S   S:X  a  MQ  U R                  S5        [         U   nU" U6 $ )	zParse a function call.zUnknown function 'z' in expression 'z'. Allowed functions: z, r/   r   r1   r3   )r   r:   r   joinsortedkeysrY   rQ   appendr]   rR   )r   r   argsfuncs       r   r   &_ExpressionParser._parse_function_call  s   ))$TF*;DII; G&&*ii7I7N7N7P0Q&R%SU 
 	X!# )d.@.@.Cx.OKK((*+$$0T5G5G5Jg5UD,,./ $$0T5G5G5Jg5U 	X!$'T{r   )rQ   r   rP   Nr@   rD   )rW   rA   rB   z	str | int)rB   
sympy.Expr)r   rA   rB   r   )rE   rF   rG   rH   rI   r   rR   rY   r_   r]   rd   rn   rr   rw   r   rJ   rK   r   r   rM   rM   n   s;    $8&. 
% _Dr   rM   c                    U R                  5       (       a  [        R                  " U SSS9$ [        U 5      nUR	                  5       $ )a  Parse a string into a SymPy expression for symbolic dimensions.

This parser is safe and does not use eval().

Supports:
    - Basic arithmetic: +, -, *, /, //, %, **
    - Functions: max(), min(), floor(), sqrt()
    - Symbolic variables (identifiers)
    - Integer literals
    - Parentheses for grouping

Args:
    value: The string to parse.

Returns:
    A SymPy expression representing the parsed string.

Raises:
    ValueError: If the expression contains unsupported constructs.
Trz   )isidentifierro   r   rM   r_   )rX   parsers     r   r   r     s<    . ||E4$??u%F<<>r   )rX   rA   rB   r   )rI   
__future__r   collections.abcr   ro   __all__r   r	   r
   r   r   r   __annotations__r   rM   r   rK   r   r   <module>r      s    # $    99999999[[JJ9999	< 8 	K
 K
\m m`r   