o
    r::j&                  	   @  s   U d Z ddlmZ ddlmZ ddlZdgZejejejejej	ej
ejejdZded< G d	d
 d
ZG dd dZdddZdS )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                   @  s8   e Zd ZdZdddZdd	d
ZdddZdddZdS )_ExpressionTokenizerzjTokenizer for symbolic dimension expressions.

    This is a safe tokenizer that does not use eval().
    textstrreturnNonec                 C  s   || _ d| _t|| _d S )Nr   )r   poslenlengthselfr    r   _/home/nk/hobo-godmode/plappi-mvp/.venv/lib/python3.10/site-packages/onnx_ir/_symbolic_shapes.py__init__&   s   z_ExpressionTokenizer.__init__
str | Nonec                 C  s$   |    | j| jkrdS | j| j S )z3Peek at the current character without consuming it.N)_skip_whitespacer   r   r   r   r   r   r   peek+   s   z_ExpressionTokenizer.peekc                 C  sV   | j | jk r%| j| j   r)|  j d7  _ | j | jk r'| j| j   sdS dS dS dS )zSkip whitespace characters.   N)r   r   r   isspacer   r   r   r   r   2   s   ,z%_ExpressionTokenizer._skip_whitespacetuple[str, str | int] | Nonec                 C  s  |    | j| jkrdS | j| j }| rH| j}| j| jk r<| j| j  r<|  jd7  _| j| jk r<| j| j  s'dt| j|| j fS | sP|dkr| j}| j| jk r| j| j  si| j| j dv r|  jd7  _| j| jk r| j| j  si| j| j dv sid| j|| j fS | jd | jk r| j| j| jd  }|dv r|  jd7  _d	|fS |d
v r|  jd7  _d	|fS |dkr|  jd7  _dS |dkr|  jd7  _dS |dkr|  jd7  _dS td| d| j d| j d)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)   ))RPARENr+   ,)COMMAr-   zUnexpected character 'z' at position  in expression '')	r   r   r   r   isdigitintisalphaisalnum
ValueError)r   charstarttwo_charr   r   r   	get_token7   sT   z_ExpressionTokenizer.get_tokenNr   r   r   r   )r   r   r   r   )r   r!   )__name__
__module____qualname____doc__r   r   r   r9   r   r   r   r   r       s    


r   c                   @  st   e Zd ZdZdddZd dd	Zd!ddZd"ddZd"ddZd"ddZ	d"ddZ
d"ddZd"ddZd#ddZdS )$_ExpressionParserab  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)*
    r   r   r   r   c                 C  s"   t || _|| _d | _|   d S )N)r   	tokenizerr   current_token_advancer   r   r   r   r      s   
z_ExpressionParser.__init__c                 C  s   | j  | _dS )zAdvance to the next token.N)rA   r9   rB   r   r   r   r   rC      s   z_ExpressionParser._advance
token_type	str | intc                 C  sN   | j du s| j d |krtd| d| j  d| j d| j d }|   |S )z,Expect a specific token type and consume it.Nr   z	Expected z	 but got r/   r0   r   )rB   r5   r   rC   )r   rD   valuer   r   r   _expect   s   
z_ExpressionParser._expect
sympy.Exprc                 C  s0   |   }| jdurtd| j d| j d|S )z3Parse the expression and return a SymPy expression.NUnexpected token z at end of expression 'r0   )_parse_exprrB   r5   r   )r   resultr   r   r   parse   s   
z_ExpressionParser.parsec                 C  s   |   }| jdurD| jd dkrD| jd dv rD| jd }|   |   }|dkr-|| }n|| }| jdurD| jd dkrD| jd dv s|S )z&Parse an expression (handles + and -).Nr   r(   r   )+-rM   )_parse_termrB   rC   r   leftoprightr   r   r   rJ      s   




z_ExpressionParser._parse_exprc                 C  s   |   }| jdur[| jd dkr[| jd dv r[| jd }|   |   }|dkr-|| }n|dkr6|| }n|dkrBt|| }nt||}| jdur[| jd dkr[| jd dv s|S )	z#Parse a term (handles *, /, //, %).Nr   r(   r   >   *%/r&   rT   rV   r&   )_parse_powerrB   rC   sympyr	   r   rP   r   r   r   rO      s$   




z_ExpressionParser._parse_termc                 C  sJ   |   }| jdur#| jd dkr#| jd dkr#|   |  }|| S |S )z&Parse a power expression (handles **).Nr   r(   r   r'   )_parse_unaryrB   rC   rW   )r   baseexponentr   r   r   rW      s   
z_ExpressionParser._parse_powerc                 C  s@   | j dur| j d dkr| j d dkr|   |   S |  S )z+Parse a unary expression (handles unary -).Nr   r(   r   rN   )rB   rC   rY   _parse_primaryr   r   r   r   rY      s   

z_ExpressionParser._parse_unaryc                 C  s   | j du rtd| j d| j \}}|dkr |   t|S |dkrJ|}t|ts-J |   | j durB| j d dkrB| |S tj	|ddd	S |dkr]|   | 
 }| d
 |S td| j  d| j d)z\Parse a primary expression (number, identifier, function call, or parenthesized expression).NzUnexpected end of expression 'r0   r"   r$   r   r*   Tintegerpositiver,   rI   r/   )rB   r5   r   rC   rX   Integer
isinstancer   _parse_function_callSymbolrJ   rG   )r   rD   token_valuenameexprr   r   r   r\      s&   




z _ExpressionParser._parse_primaryre   c                 C  s   |t vrtd| d| j ddtt   | d g }| jdurV| jd dkrV|| 	  | jdurV| jd d	krV| 
  || 	  | jdurV| jd d	ks?| d t | }|| S )
zParse a function call.zUnknown function 'z' in expression 'z'. Allowed functions: z, r*   Nr   r,   r.   )r   r5   r   joinsortedkeysrG   rB   appendrJ   rC   )r   re   argsfuncr   r   r   rb     s"   

z&_ExpressionParser._parse_function_callNr:   r;   )rD   r   r   rE   )r   rH   )re   r   r   rH   )r<   r=   r>   r?   r   rC   rG   rL   rJ   rO   rW   rY   r\   rb   r   r   r   r   r@   n   s    





	



"r@   rF   r   r   rH   c                 C  s(   |   rtj| dddS t| }| S )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.
    Tr]   )isidentifierrX   rc   r@   rL   )rF   parserr   r   r   r     s   )rF   r   r   rH   )r?   
__future__r   collections.abcr   rX   __all__r   r   r	   r
   r   r   __annotations__r   r@   r   r   r   r   r   <module>   s&   N 1