Packages

ex_cldr

2.11.0
2.47.5 2.47.4 2.47.3 2.47.2 2.47.1 2.47.0 2.46.0 2.45.2 2.45.1 2.45.0 2.44.1 2.44.0 2.43.2 2.43.1 2.43.0 2.42.0 2.41.1 2.41.0 2.40.4 2.40.3 2.40.2 2.40.1 2.40.0 2.39.2 2.39.1 2.39.0 2.38.1 2.38.0 2.37.5 2.37.4 2.37.3 retired 2.37.2 2.37.1 2.37.0 2.36.0 2.35.1 2.35.0 retired 2.34.2 2.34.1 2.34.0 2.33.2 2.33.1 2.33.1-rc.0 2.33.0 2.32.1 2.32.0 2.31.0 2.30.0 2.29.0 2.28.0 2.27.1 2.27.0 retired 2.26.3 2.26.2 2.26.1 2.26.0 2.25.0 2.24.2 2.24.1 2.24.0 2.24.0-rc.6 2.24.0-rc.5 2.24.0-rc.4 2.24.0-rc.3 2.24.0-rc.2 2.24.0-rc.1 2.24.0-rc.0 2.23.2 2.23.1 2.23.0 2.22.1 2.22.0 2.21.0 2.20.0 2.20.0-rc.3 2.20.0-rc.2 2.20.0-rc.1 2.20.0-rc.0 2.19.1 2.19.0 2.18.2 2.18.1 2.18.0 2.18.0-rc.0 2.17.2 2.17.1 2.17.0 2.16.2 2.16.1 2.16.1-rc.0 2.16.0 2.15.0 2.14.1 2.14.0 2.14.0-rc.0 2.13.0 2.12.1 2.12.0 2.11.1 2.11.0 2.10.2 2.10.1 2.10.0 retired 2.9.0 2.8.1 2.8.0 2.7.2 2.7.1 2.7.0 2.6.2 2.6.1 2.6.0 2.5.0 2.4.3 2.4.2 2.4.1 2.4.0 2.3.2 2.3.1 2.3.0 2.2.7 2.2.6 2.2.5 2.2.4 2.2.3 2.2.2 2.2.1 2.2.0 2.1.0 2.0.4 2.0.3 2.0.2 2.0.1 2.0.0 2.0.0-rc.3 retired 2.0.0-rc.2 retired 2.0.0-rc.1 retired 2.0.0-rc.0 retired 1.8.2 1.8.1 1.8.0 1.7.1 1.7.0 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.2 1.5.1 1.5.0 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 retired 1.4.0-rc.3 retired 1.4.0-rc.2 retired 1.4.0-rc.1 retired 1.4.0-rc.0 retired 1.3.2 1.3.1 1.3.0 1.2.0 1.1.0 1.0.0 1.0.0-rc.3 retired 1.0.0-rc.2 retired 1.0.0-rc.1 retired 1.0.0-rc.0 retired 0.13.1 0.13.0 0.12.2 retired 0.12.1 retired 0.12.0 retired 0.11.0 retired 0.10.0 retired 0.9.0 retired 0.8.3 retired 0.8.2 retired 0.8.1 retired 0.8.0 retired 0.7.0 retired 0.6.2 retired 0.6.1 retired 0.6.0 retired 0.5.2 retired 0.5.1 retired 0.5.0 retired 0.4.2 retired 0.4.1 retired 0.4.0 retired 0.3.0 retired 0.2.1 retired 0.2.0 retired 0.1.3 retired 0.1.2 retired 0.1.1 retired 0.1.0 retired 0.0.20 retired 0.0.19 retired 0.0.18 retired 0.0.17 retired 0.0.16 retired 0.0.15 retired 0.0.14 retired 0.0.13 retired 0.0.12 retired 0.0.11 retired 0.0.10 retired 0.0.8 retired 0.0.7 retired 0.0.6 retired 0.0.5 retired 0.0.4 retired 0.0.3 retired

Common Locale Data Repository (CLDR) functions for Elixir to localize and format numbers, dates, lists, messages, languages, territories and units with support for over 700 locales for internationalized (i18n) and localized (L10N) applications.

Current section

Files

Jump to
ex_cldr src plural_rules_parser.yrl
Raw

src/plural_rules_parser.yrl

% Parse the CLDR Plural Rules definitions and return an Elixir AST
% Rules syntax and semantics are defined in
% http://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules
%
% condition = and_condition ('or' and_condition)*
% samples = ('@integer' sampleList)?
% ('@decimal' sampleList)?
% 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)*
% range = value'..'value
% sampleList = sampleRange (',' sampleRange)* (',' ('…'|'...'))?
% sampleRange = decimalValue ('~' decimalValue)?
% value = digit+
% decimalValue = value ('.' value)?
% digit = 0|1|2|3|4|5|6|7|8|9
Nonterminals plural_rule condition and_condition relation is_relation in_relation within_relation
conditional expression range_list range_or_value range value samples sample_list sample_range.
Terminals mod is_op not_op sample operand tilde or_predicate and_predicate range_op
comma decimal integer ellipsis equals in within_op not_equals.
Rootsymbol plural_rule.
Right 100 mod.
Nonassoc 200 equals not_equals.
Left 300 and_predicate.
Left 400 or_predicate.
plural_rule -> condition samples : append({rule, '$1'}, '$2').
plural_rule -> condition : [{rule, '$1'}].
plural_rule -> samples : '$1'.
condition -> and_condition or_predicate condition : or_function('$1', '$3').
condition -> and_condition : '$1'.
and_condition -> relation and_predicate and_condition : and_function('$1', '$3').
and_condition -> relation : '$1'.
relation -> is_relation : '$1'.
relation -> in_relation : '$1'.
relation -> within_relation : '$1'.
is_relation -> expression is_op value : or_range_list('$1', '$3').
is_relation -> expression is_op not_op value : not_function(or_range_list('$1', '$4')).
in_relation -> expression not_equals range_list : not_function(or_range_list('$1', '$3')).
in_relation -> expression conditional range_list : or_range_list('$1', '$3').
in_relation -> expression not_op in range_list : not_function(or_range_list('$1', '$4')).
within_relation -> expression within_op range_list : or_range_list('$1', '$3').
within_relation -> expression not_op within_op range_list : not_function(or_range_list('$1', '$4')).
conditional -> in : 'in'.
conditional -> equals : '='.
% TODO It would be good to keep track of the operands used so we only generate those ones
% TODO We need to generate variables for the mod expressions to avoid duplicate calculations too
expression -> operand mod value : mod('$1', '$3').
expression -> operand : operand('$1').
range_list -> range_or_value comma range_list : append('$1', '$3').
range_list -> range_or_value : '$1'.
range_or_value -> range : '$1'.
range_or_value -> value : '$1'.
range -> value range_op value : range('$1', '$3').
value -> integer : unwrap('$1').
value -> decimal : unwrap('$1').
samples -> sample sample_list samples : append({unwrap('$1'), '$2'}, '$3').
samples -> sample sample_list : [{unwrap('$1'), '$2'}].
sample_list -> sample_range comma sample_list : append('$1', '$3').
sample_list -> sample_range : ['$1'].
sample_range -> value tilde value : range('$1', '$3').
sample_range -> value : '$1'.
sample_range -> ellipsis : 'ellipsis'.
Erlang code.
-export([kernel_context/0]).
% mod function will calculate the modulo in Java fashion
% for floats and decimals so that mod(4.3, 3) == 1.3
% The function itself is defined in Cldr.Math
mod(Operand, Value) ->
{'mod', kernel_context(), [operand(Operand), Value]}.
% Return a reference to an operand
operand(Operand) ->
{atomize(Operand), [], 'Elixir'}.
% 'and' function
and_function(A, B) ->
{'and', kernel_context(), [A, B]}.
% 'or' function
or_function(A, B) ->
{'or', kernel_context(), [A, B]}.
% 'not' function
not_function(A) ->
{'!', kernel_context(), [A]}.
% Range syntax
range(Start, End) ->
{'..', kernel_context(), [Start, End]}.
% Inclusion forms
% -> for a range. call a helper function `within`
% so we can handle integers and floats/decimals
% separately
conditional(equals, A, B = {'..', _C, [_From, _To]}) ->
{'within', kernel_context(), [A, B]};
% -> for an expression
% NOTE this will calculate the expression each time which is
% inefficient. But parser isn't the right place to unwrap that.
% NOTE REMOVED DUE TO DIALYZER ERROR saying this can never match.
% tests still pass without it.
% conditional({'mod', [_C], [{_L}]}, A, B) ->
% {'==', kernel_context(), [A, B]};
% -> for a value
conditional(equals, A, B) ->
{'==', kernel_context(), [A, B]}.
% Convert a range list into a postfix 'or' form
% Just two items in the list
or_range_list(Operand, [A, B]) ->
or_function(conditional(equals, Operand, A),
conditional(equals, Operand, B));
% Many items in a list
or_range_list(Operand, [A | B]) ->
or_function(conditional(equals, Operand, A),
or_range_list(Operand, B));
% When theres only one value
or_range_list(Operand, Value) ->
conditional(equals, Operand, Value).
% Append to build up a list of ranges or values
append(A, B) when is_list(A) and is_list(B) ->
A ++ B;
append(A, B) when is_list(A) and not is_list(B)->
A ++ [B];
append(A, B) when not is_list(A) and is_list(B) ->
[A] ++ B;
append(A, B) when not is_list(A) and not is_list(B) ->
[A, B].
% Return a token value
unwrap({_,_,V}) -> V.
% Elixir Kernel Context
kernel_context() ->
[{context, 'Elixir'}, {import, 'Elixir.Kernel'}].
% Atomize a token value
atomize(Token) ->
list_to_atom(unwrap(Token)).