o
    miZ                  	   @  s  U d Z ddlmZ ddlZddlZddlmZmZ ddlm	Z	m
Z
mZ dZdZdeddZG dd dZdfddZdgddZdfddZdhddZdhd d!Zdid%d&ZG d'd( d(eZh d)Zded*ejfd+ed,d-e d.fd/ed0fd1ed2fd3ed4ejfgZd5ed6< djd9d:Z	dkdld?d@ZdkdmdAdBZ dndEdFZ!dodIdJZ"dpdLdMZ#dqdQdRZ$G dSdT dTZ%dUdV Z&dWdX Z'dYdZ Z(G d[d\ d\Z)G d]d^ d^e)Z*G d_d` d`e)Z+G dadb dbe+Z,G dcdd dde)Z-dS )rz
babel.numbers
~~~~~~~~~~~~~

CLDR Plural support.  See UTS #35.

:copyright: (c) 2013-2026 by the Babel Team.
:license: BSD, see LICENSE for more details.
    )annotationsN)IterableMapping)AnyCallableLiteral)zeroonetwofewmanyotherr   sourcefloat | decimal.DecimalreturnMtuple[decimal.Decimal | int, int, int, int, int, int, Literal[0], Literal[0]]c                 C  s   t | }t|}t|tr||kr|}ntt|}t|tjrY| }|j}|dk r3|j	|d nd}d
dd |D }|d}t|}t|}	t|pPd}
t|pVd}nd } }	 }
}d }}||||	|
|||fS )u  Extract operands from a decimal, a float or an int, according to `CLDR rules`_.

    The result is an 8-tuple (n, i, v, w, f, t, c, e), where those symbols are as follows:

    ====== ===============================================================
    Symbol Value
    ------ ---------------------------------------------------------------
    n      absolute value of the source number (integer and decimals).
    i      integer digits of n.
    v      number of visible fraction digits in n, with trailing zeros.
    w      number of visible fraction digits in n, without trailing zeros.
    f      visible fractional digits in n, with trailing zeros.
    t      visible fractional digits in n, without trailing zeros.
    c      compact decimal exponent value: exponent of the power of 10 used in compact decimal formatting.
    e      currently, synonym for ‘c’. however, may be redefined in the future.
    ====== ===============================================================

    .. _`CLDR rules`: https://www.unicode.org/reports/tr35/tr35-61/tr35-numbers.html#Operands

    :param source: A real number
    :type source: int|float|decimal.Decimal
    :return: A n-i-v-w-f-t-c-e tuple
    :rtype: tuple[decimal.Decimal, int, int, int, int, int, int, int]
    r   N  c                 s  s    | ]}t |V  qd S Nstr).0dr   r   F/home/kim/smarthome/.venv/lib/python3.10/site-packages/babel/plural.py	<genexpr>G       z#extract_operands.<locals>.<genexpr>0)absint
isinstancefloatdecimalDecimalr   as_tupleexponentdigitsjoinrstriplen)r   niZ	dec_tupleexpZfraction_digitsZtrailingZno_trailingvwftcer   r   r   extract_operands   s&   

r2   c                   @  sp   e Zd ZdZdZd ddZd!d
dZed"ddZe	d#ddZ
e	d$ddZd%ddZd&ddZd'ddZdS )(
PluralRuleaf  Represents a set of language pluralization rules.  The constructor
    accepts a list of (tag, expr) tuples or a dict of `CLDR rules`_. The
    resulting object is callable and accepts one parameter with a positive or
    negative number (both integer and float) for the number that indicates the
    plural form for a string and returns the tag for the format:

    >>> rule = PluralRule({'one': 'n is 1'})
    >>> rule(1)
    'one'
    >>> rule(2)
    'other'

    Currently the CLDR defines these tags: zero, one, two, few, many and
    other where other is an implicit default.  Rules should be mutually
    exclusive; for a given numeric value, only one rule should apply (i.e.
    the condition should only be true for one of the plural rule elements.

    .. _`CLDR rules`: https://www.unicode.org/reports/tr35/tr35-33/tr35-numbers.html#Language_Plural_Rules
    )abstract_funcrules-Mapping[str, str] | Iterable[tuple[str, str]]r   Nonec                 C  s   t |tr	| }t }g | _t|D ]/\}}|tvr"td|||v r.td|d|| t	|j
}|rB| j||f qdS )a$  Initialize the rule instance.

        :param rules: a list of ``(tag, expr)``) tuples with the rules
                      conforming to UTS #35 or a dict with the tags as keys
                      and expressions as values.
        :raise RuleError: if the expression is malformed
        zunknown tag ztag z defined twiceN)r   r   itemssetr4   sorted_plural_tags
ValueErroradd_Parserastappend)selfr6   foundkeyexprr@   r   r   r   __init__j   s   


zPluralRule.__init__r   c                   s6   | j  d fddtD }dt| j d|dS )N, c                 3  s*    | ]}| v r| d  |  V  qdS )z: Nr   r   tagr6   r   r   r      s   ( z&PluralRule.__repr__.<locals>.<genexpr>< >)r6   r&   r<   type__name__)rB   argsr   rJ   r   __repr__   s   zPluralRule.__repr__:Mapping[str, str] | Iterable[tuple[str, str]] | PluralRulec                 C  s   t |tr|S | |S )a
  Create a `PluralRule` instance for the given rules.  If the rules
        are a `PluralRule` object, that object is returned.

        :param rules: the rules as list or dict, or a `PluralRule` object
        :raise RuleError: if the expression is malformed
        )r   r3   )clsr6   r   r   r   parse   s   
zPluralRule.parseMapping[str, str]c                   s   t  j  fdd| jD S )zThe `PluralRule` as a dict of unicode plural rules.

        >>> rule = PluralRule({'one': 'n is 1'})
        >>> rule.rules
        {'one': 'n is 1'}
        c                   s   i | ]	\}}| |qS r   r   )r   rI   r@   _compiler   r   
<dictcomp>   s    z$PluralRule.rules.<locals>.<dictcomp>)_UnicodeCompilercompiler4   rB   r   rV   r   r6      s   zPluralRule.rulesfrozenset[str]c                 C  s   t dd | jD S )zA set of explicitly defined tags in this rule.  The implicit default
        ``'other'`` rules is not part of this set unless there is an explicit
        rule for it.
        c                 s  s    | ]}|d  V  qdS )r   Nr   )r   r*   r   r   r   r      r   z"PluralRule.tags.<locals>.<genexpr>)	frozensetr4   r[   r   r   r   tags   s   zPluralRule.tagslist[tuple[str, Any]]c                 C  s   | j S r   r4   r[   r   r   r   __getstate__      zPluralRule.__getstate__r4   c                 C  s
   || _ d S r   r`   )rB   r4   r   r   r   __setstate__      
zPluralRule.__setstate__r)   r   c                 C  s   t | ds
t| | _| |S )Nr5   )hasattr	to_pythonr5   )rB   r)   r   r   r   __call__   s   


zPluralRule.__call__N)r6   r7   r   r8   )r   r   )r6   rR   r   r3   )r   rU   )r   r\   )r   r_   )r4   r_   r   r8   )r)   r   r   r   )rO   
__module____qualname____doc__	__slots__rF   rQ   classmethodrT   propertyr6   r^   ra   rc   rg   r   r   r   r   r3   S   s    




r3   rulerR   r   c                 C  sV   t  j}dg}t| jD ]\}}||| d|d q|dt  d|S )a  Convert a list/dict of rules or a `PluralRule` object into a JavaScript
    function.  This function depends on no external library:

    >>> to_javascript({'one': 'n is 1'})
    "(function(n) { return (n == 1) ? 'one' : 'other'; })"

    Implementation detail: The function generated will probably evaluate
    expressions involved into range operations multiple times.  This has the
    advantage that external helper functions are not required and is not a
    big performance hit for these simple calculations.

    :param rule: the rules as list or dict, or a `PluralRule` object
    :raise RuleError: if the expression is malformed
    z(function(n) { return  ?  : z%r; })r   )_JavaScriptCompilerrZ   r3   rT   r4   rA   _fallback_tagr&   )rn   Zto_jsresultrI   r@   r   r   r   to_javascript   s   
rt   (Callable[[float | decimal.Decimal], str]c                 C  s   t tttd}t j}ddg}t| jD ]\}}|	d|| dt
| q|	dt td|dd	}t|| |d
 S )a<  Convert a list/dict of rules or a `PluralRule` object into a regular
    Python function.  This is useful in situations where you need a real
    function and don't are about the actual rule object:

    >>> func = to_python({'one': 'n is 1', 'few': 'n in 2..4'})
    >>> func(1)
    'one'
    >>> func(3)
    'few'
    >>> func = to_python({'one': 'n in 1,11', 'few': 'n in 3..10,13..19'})
    >>> func(11)
    'one'
    >>> func(15)
    'few'

    :param rule: the rules as list or dict, or a `PluralRule` object
    :raise RuleError: if the expression is malformed
    )INZWITHINZMODr2   zdef evaluate(n):z- n, i, v, w, f, t, c, e = extract_operands(n)z if (z
): return z return 
z<rule>execevaluate)in_range_listwithin_range_listcldr_modulor2   _PythonCompilerrZ   r3   rT   r4   rA   r   rr   r&   eval)rn   	namespaceZto_python_funcrs   rI   r@   coder   r   r   rf      s    
rf   c                   s   t | } | jthB  t j} fddtD j}dt  dg}| j	D ]\}}|
|| d|| d q%|
|t d d|S )	a  The plural rule as gettext expression.  The gettext expression is
    technically limited to integers and returns indices rather than tags.

    >>> to_gettext({'one': 'n is 1', 'two': 'n is 2'})
    'nplurals=3; plural=((n == 1) ? 0 : (n == 2) ? 1 : 2);'

    :param rule: the rules as list or dict, or a `PluralRule` object
    :raise RuleError: if the expression is malformed
    c                   s   g | ]}| v r|qS r   r   rH   Z	used_tagsr   r   
<listcomp>      zto_gettext.<locals>.<listcomp>z	nplurals=z
; plural=(ro   rp   z);r   )r3   rT   r^   rr   _GettextCompilerrZ   r<   indexr(   r4   rA   r&   )rn   rW   Z
_get_indexrs   rI   r@   r   r   r   
to_gettext   s   

 
r   num
range_list+Iterable[Iterable[float | decimal.Decimal]]boolc                 C  s   | t | ko
t| |S )a  Integer range list test.  This is the callback for the "in" operator
    of the UTS #35 pluralization rule language:

    >>> in_range_list(1, [(1, 3)])
    True
    >>> in_range_list(3, [(1, 3)])
    True
    >>> in_range_list(3, [(1, 3), (5, 8)])
    True
    >>> in_range_list(1.2, [(1, 4)])
    False
    >>> in_range_list(10, [(1, 4)])
    False
    >>> in_range_list(10, [(1, 4), (6, 8)])
    False
    )r   r{   r   r   r   r   r   rz        rz   c                   s   t  fdd|D S )a  Float range test.  This is the callback for the "within" operator
    of the UTS #35 pluralization rule language:

    >>> within_range_list(1, [(1, 3)])
    True
    >>> within_range_list(1.0, [(1, 3)])
    True
    >>> within_range_list(1.2, [(1, 4)])
    True
    >>> within_range_list(8.8, [(1, 4), (7, 15)])
    True
    >>> within_range_list(10, [(1, 4)])
    False
    >>> within_range_list(10.5, [(1, 4), (20, 30)])
    False
    c                 3  s,    | ]\}}|   ko|kn  V  qd S r   r   )r   Zmin_Zmax_r   r   r   r   6  s   * z$within_range_list.<locals>.<genexpr>)anyr   r   r   r   r{   "  r   r{   ar    bc                 C  s@   d}| dk r| d9 } d}|dk r|d9 }| | }|r|d9 }|S )zJavaish modulo.  This modulo operator returns the value with the sign
    of the dividend rather than the divisor like Python does:

    >>> cldr_modulo(-3, 5)
    -3
    >>> cldr_modulo(-3, -5)
    -3
    >>> cldr_modulo(3, 5)
    3
    r      r   )r   r   reverservr   r   r   r|   9  s   r|   c                   @  s   e Zd ZdZdS )	RuleErrorzRaised if a rule is malformed.N)rO   rh   ri   rj   r   r   r   r   r   P  s    r   >   r)   r1   r*   r,   r0   r-   r/   r.   z\s+wordz"\b(and|or|is|(?:with)?in|not|mod|[r   z])\bvaluez\d+symbolz%|,|!=|=ellipsisz\.{2,3}|\u2026z(list[tuple[str | None, re.Pattern[str]]]_RULESslist[tuple[str, str]]c                 C  s   |  dd } g }d}t| }||k rBtD ]\}}|| |}|d ur4| }|r2||| f  n
qtd| | ||k s|d d d S )N@r   z3malformed CLDR pluralization rule.  Got unexpected r   )splitr(   r   matchendrA   groupr   )r   rs   posr   tokrn   r   r   r   r   tokenize_ruleh  s    
r   tokenstype_
str | Nonelist[tuple[str, str]] | boolc                 C  s,   | o| d d |ko|d u p| d d |kS )Nr   r   r   r   r   r   r   r   r   r   test_next_tokenz  s   ,r   c                 C  s   t | ||r
|  S d S r   )r   popr   r   r   r   
skip_token  s   r   r   #tuple[Literal['value'], tuple[int]]c                 C  
   d| ffS )Nr   r   )r   r   r   r   
value_node  rd   r   nametuple[str, tuple[()]]c                 C  s   | dfS )Nr   r   )r   r   r   r   
ident_node  s   r   Ituple[Literal['range_list'], Iterable[Iterable[float | decimal.Decimal]]]c                 C  s   d| fS )Nr   r   )r   r   r   r   range_list_node  s   r   r   tuple[Any, ...]-tuple[Literal['not'], tuple[tuple[Any, ...]]]c                 C  r   )Nnotr   )r   r   r   r   negate  rd   r   c                   @  sb   e Zd ZdZdd ZdddZdd Zd	d
 Zdd Zdd Z	dd Z
dd Zdd Zdd ZdS )r?   u  Internal parser.  This class can translate a single rule into an abstract
    tree of tuples. It implements the following grammar::

        condition     = and_condition ('or' and_condition)*
                        ('@integer' samples)?
                        ('@decimal' samples)?
        and_condition = relation ('and' relation)*
        relation      = is_relation | in_relation | within_relation
        is_relation   = expr 'is' ('not')? value
        in_relation   = expr (('not')? 'in' | '=' | '!=') range_list
        within_relation = expr ('not')? 'within' range_list
        expr          = operand (('mod' | '%') value)?
        operand       = 'n' | 'i' | 'f' | 't' | 'v' | 'w'
        range_list    = (range | value) (',' range_list)*
        value         = digit+
        digit         = 0|1|2|3|4|5|6|7|8|9
        range         = value'..'value
        samples       = sampleRange (',' sampleRange)* (',' ('…'|'...'))?
        sampleRange   = decimalValue '~' decimalValue
        decimalValue  = value ('.' value)?

    - Whitespace can occur between or around any of the above tokens.
    - Rules should be mutually exclusive; for a given numeric value, only one
      rule should apply (i.e. the condition should only be true for one of
      the plural rule elements).
    - The in and within relations can take comma-separated lists, such as:
      'n in 3,5,7..15'.
    - Samples are ignored.

    The translator parses the expression on instantiation into an attribute
    called `ast`.
    c                 C  sF   t || _| jsd | _d S |  | _| jr!td| jd d d S )NzExpected end of rule, got r   r   )r   r   r@   	conditionr   )rB   stringr   r   r   rF     s   

z_Parser.__init__Nc                 C  sj   t | j||}|d ur|S |d u rt|d u r|p|}| js&td| dtd| d| jd d )Nz	expected z but end of rule reachedz	 but got r   r   )r   r   reprr   )rB   r   r   termtokenr   r   r   expect  s   z_Parser.expectc                 C  8   |   }t| jddrd||   ff}t| jdds|S )Nr   or)and_conditionr   r   rB   opr   r   r   r     
   z_Parser.conditionc                 C  r   )Nr   and)relationr   r   r   r   r   r   r     r   z_Parser.and_conditionc                 C  s   |   }t| jddrt| jddrdnd}|||  ffS t| jdd}d}t| jddr1d}nt| jddsC|r>td| |S d|||  ff}|rRt|S |S )	Nr   isr   ZisnotinZwithinz#Cannot negate operator based rules.r   )rE   r   r   r   r   newfangled_relationr   r   )rB   leftr   negatedmethodr   r   r   r   r     s   
z_Parser.relationc                 C  sR   t | jddr
d}nt | jddrd}ntddd||  ff}|r't|S |S )	Nr   =Fz!=Tz'Expected "=" or "!=" or legacy relationr   r   )r   r   r   r   r   )rB   r   r   r   r   r   r   r     s   z_Parser.newfangled_relationc                 C  s(   |   }t| jdr||   fS ||fS )Nr   )r   r   r   )rB   r   r   r   r   range_or_value  s   z_Parser.range_or_valuec                 C  s<   |   g}t| jddr||    t| jddst|S )Nr   ,)r   r   r   rA   r   )rB   r   r   r   r   r     s
   
z_Parser.range_listc                 C  s|   t | jd}|d u s|d tvrtd|d }t | jddr)d|df|  ffS t | jddr:d|df|  ffS t|S )Nr   r   zExpected identifier variablemodr   r   %)r   r   _VARSr   r   r   )rB   r   r   r   r   r   rE     s   z_Parser.exprc                 C  s   t t| dd S )Nr   r   )r   r   r   r[   r   r   r   r     s   z_Parser.value)NN)rO   rh   ri   rj   rF   r   r   r   r   r   r   r   rE   r   r   r   r   r   r?     s    !


r?   c                       fddS )%Compiler factory for the `_Compiler`.c                   s    |  ||  |f S r   rZ   )rB   r   righttmplr   r   <lambda>  r   z"_binary_compiler.<locals>.<lambda>r   r   r   r   r   _binary_compiler     r   c                   r   )r   c                   s    |  | S r   r   )rB   xr   r   r   r     s    z!_unary_compiler.<locals>.<lambda>r   r   r   r   r   _unary_compiler  r   r   c                 C     dS )Nr   r   r   r   r   r   r         r   c                   @  s   e Zd ZdZdd Zdd Zdd Zdd Zdd Zd	d Z	d
d Z
dd Zdd Zdd ZedZedZedZedZedZedZdd ZdS )	_CompilerzZThe compilers are able to transform the expressions into multiple
    output formats.
    c                 C  s   |\}}t | d| | S )NZcompile_)getattr)rB   argr   rP   r   r   r   rZ   %  s   z_Compiler.compilec                 C  r   )Nr)   r   r   r   r   r   r   )  r   z_Compiler.<lambda>c                 C  r   )Nr*   r   r   r   r   r   r   *  r   c                 C  r   )Nr,   r   r   r   r   r   r   +  r   c                 C  r   )Nr-   r   r   r   r   r   r   ,  r   c                 C  r   )Nr.   r   r   r   r   r   r   -  r   c                 C  r   )Nr/   r   r   r   r   r   r   .  r   c                 C  r   )Nr0   r   r   r   r   r   r   /  r   c                 C  r   )Nr1   r   r   r   r   r   r   0  r   c                 C  s   t |S r   r   )r   r,   r   r   r   r   1  s    z
(%s && %s)z
(%s || %s)z(!%s)z
(%s %% %s)z
(%s == %s)z
(%s != %s)c                 C  s   t  r   )NotImplementedError)rB   r   rE   r   r   r   r   compile_relation9  rb   z_Compiler.compile_relationN)rO   rh   ri   rj   rZ   	compile_n	compile_i	compile_v	compile_w	compile_f	compile_tZ	compile_cZ	compile_eZcompile_valuer   compile_and
compile_orr   compile_notcompile_mod
compile_iscompile_isnotr   r   r   r   r   r      s&    r   c                   @  s8   e Zd ZdZedZedZedZedZ	dd Z
dS )	r}   z!Compiles an expression to Python.z(%s and %s)z
(%s or %s)z(not %s)zMOD(%s, %s)c                   s<   d  fdd|d D }|  d | d| dS )Nr   c                 3  s2    | ]\}}d   | d  | dV  qdS )(rG   )Nr   )r   r   r   r[   r   r   r   F  s    "
z3_PythonCompiler.compile_relation.<locals>.<genexpr>r   r   z, [z]))r&   upperrZ   )rB   r   rE   r   rangesr   r[   r   r   E  s    z _PythonCompiler.compile_relationN)rO   rh   ri   rj   r   r   r   r   r   r   r   r   r   r   r   r}   =  s    r}   c                   @  s.   e Zd ZdZejZeZeZ	eZ
eZdd ZdS )r   z)Compile into a gettext plural expression.c                 C  s   g }|  |}|d D ]<}|d |d kr'|d| d|  |d  d q|  |d }|  |d }|d| d| d| d| d	 qdd	| dS )
Nr   r   r   z == r   z >=  && z <= z || )rZ   rA   r&   )rB   r   rE   r   r   itemminmaxr   r   r   r   U  s   
$&z!_GettextCompiler.compile_relationN)rO   rh   ri   rj   r   r   r   compile_zeror   r   r   r   r   r   r   r   r   r   L  s    r   c                   @  s0   e Zd ZdZdd ZeZeZeZeZ	dd Z
dS )rq   z/Compiles the expression to plain of JavaScript.c                 C  r   )NzparseInt(n, 10)r   r   r   r   r   r   g  r   z_JavaScriptCompiler.<lambda>c                 C  s>   t | |||}|dkr| |}d| d| d| d}|S )Nr   z
(parseInt(z	, 10) == r   r   )r   r   rZ   )rB   r   rE   r   r   r   r   r   r   m  s
   
z$_JavaScriptCompiler.compile_relationN)rO   rh   ri   rj   r   r   r   r   r   r   r   r   r   r   r   rq   b  s    rq   c                   @  sJ   e Zd ZdZedZedZedZedZedZ	dd Z
dd
dZdS )rY   z+Returns a unicode pluralization rule again.z%s is %sz%s is not %sz	%s and %sz%s or %sz	%s mod %sc                 C  s   | j |d ddiS )Nr   r   T)r   )rB   r   r   r   r   r     s   z_UnicodeCompiler.compile_notFc              	   C  s   g }|d D ])}|d |d kr| | |d  q| | |d  d| |d   q| | |r9dnd d| dd| S )Nr   r   z..z notr   rL   r   )rA   rZ   r&   )rB   r   rE   r   r   r   r   r   r   r   r     s   *,z!_UnicodeCompiler.compile_relationN)F)rO   rh   ri   rj   r   r   r   r   r   r   r   r   r   r   r   r   rY   u  s    rY   )r   r   r   r   )rn   rR   r   r   )rn   rR   r   ru   )r   r   r   r   r   r   )r   r    r   r    r   r    )r   r   r   r   r   )r   r   r   r   r   r   r   r   )r   r   r   r   r   r   )r   r   r   r   )r   r   r   r   )r   r   r   r   )r   r   r   r   ).rj   
__future__r   r!   recollections.abcr   r   typingr   r   r   r<   rr   r2   r3   rt   rf   r   rz   r{   r|   	Exceptionr   r   rZ   UNICODEr&   r   __annotations__r   r   r   r   r   r   r   r?   r   r   r   r   r}   r   rq   rY   r   r   r   r   <module>   sR    

=
`

*



	



z