Skip to content

Commit

Permalink
Add support for E PluralOperand (#407)
Browse files Browse the repository at this point in the history
* Add support for E PluralOperand

* Add the FromStr

* Fix ecma402 trait

* Apply reviewers feedback

* Add roundtrip parse/serialize test

* Fix ECMA402 test for plurals

* Move `e` to not be an operand

* Move to serialize C as `c` and switch tests to use it.

* Re-add AST node for E
  • Loading branch information
zbraniecki committed Jan 9, 2021
1 parent d0ee68b commit 2a9adbc
Show file tree
Hide file tree
Showing 12 changed files with 123 additions and 39 deletions.
1 change: 1 addition & 0 deletions components/ecma402/src/pluralrules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ pub(crate) mod internal {
w: 1,
f: 50,
t: 5,
c: 0,
},
}];
for test in tests {
Expand Down
25 changes: 23 additions & 2 deletions components/plurals/src/operands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use std::str::FromStr;
/// w: 0,
/// f: 0,
/// t: 0,
/// c: 0,
/// }, PluralOperands::from(2_usize))
/// ```
///
Expand All @@ -39,6 +40,7 @@ use std::str::FromStr;
/// w: 3,
/// f: 567,
/// t: 567,
/// c: 0,
/// }), "-1234.567".parse())
/// ```
///
Expand All @@ -53,6 +55,7 @@ use std::str::FromStr;
/// w: 2,
/// f: 45,
/// t: 45,
/// c: 0,
/// }), "123.45".parse())
/// ```
#[derive(Debug, Clone, Copy, PartialEq)]
Expand All @@ -67,6 +70,8 @@ pub struct PluralOperands {
pub f: u64,
/// Visible fraction digits without trailing zeros
pub t: u64,
/// Exponent of the power of 10 used in compact decimal formatting
pub c: usize,
}

impl PluralOperands {
Expand Down Expand Up @@ -99,6 +104,15 @@ impl From<IOError> for OperandsError {
}
}

fn get_exponent(input: &str) -> Result<(&str, usize), OperandsError> {
if let Some(e_idx) = input.find('e') {
let e = usize::from_str(&input[e_idx + 1..])?;
Ok((&input[..e_idx], e))
} else {
Ok((input, 0))
}
}

impl FromStr for PluralOperands {
type Err = OperandsError;

Expand All @@ -115,9 +129,10 @@ impl FromStr for PluralOperands {
num_fraction_digits,
fraction_digits0,
fraction_digits,
exponent,
) = if let Some(sep_idx) = abs_str.find('.') {
let int_str = &abs_str[..sep_idx];
let dec_str = &abs_str[(sep_idx + 1)..];
let (dec_str, exponent) = get_exponent(&abs_str[(sep_idx + 1)..])?;

let integer_digits = u64::from_str(int_str)?;

Expand All @@ -140,10 +155,12 @@ impl FromStr for PluralOperands {
num_fraction_digits,
fraction_digits0,
fraction_digits,
exponent,
)
} else {
let (abs_str, exponent) = get_exponent(abs_str)?;
let integer_digits = u64::from_str(abs_str)?;
(integer_digits, 0, 0, 0, 0)
(integer_digits, 0, 0, 0, 0, exponent)
};

Ok(Self {
Expand All @@ -152,6 +169,7 @@ impl FromStr for PluralOperands {
w: num_fraction_digits,
f: fraction_digits0,
t: fraction_digits,
c: exponent,
})
}
}
Expand All @@ -166,6 +184,7 @@ macro_rules! impl_integer_type {
w: 0,
f: 0,
t: 0,
c: 0,
}
}
}
Expand All @@ -187,6 +206,7 @@ macro_rules! impl_signed_integer_type {
w: 0,
f: 0,
t: 0,
c: 0,
})
}
}
Expand Down Expand Up @@ -232,6 +252,7 @@ impl From<&FixedDecimal> for PluralOperands {
w,
f,
t,
c: 0,
}
}
}
5 changes: 5 additions & 0 deletions components/plurals/src/rules/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@ pub enum Operand {
F,
/// Visible fraction digits without trailing zeros
T,
/// Compact decimal exponent value:
/// exponent of the power of 10 used in compact decimal formatting
C,
/// Currently, synonym for ‘c’. however, may be redefined in the future
E,
}

/// An incomplete AST representation of a plural rule. Comprises a vector of `RangeListItems`.
Expand Down
3 changes: 3 additions & 0 deletions components/plurals/src/rules/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub enum Token {
Integer,
Ellipsis,
Tilde,
E,
}

#[derive(Debug)]
Expand Down Expand Up @@ -165,6 +166,8 @@ impl<'l> Lexer<'l> {
Token::Ellipsis
}
b'~' => Token::Tilde,
b'e' => Token::E,
b'c' => Token::Operand(ast::Operand::C),
b => return Err(LexerError::UnknownToken(*b)),
};
return Ok(Some(token));
Expand Down
3 changes: 2 additions & 1 deletion components/plurals/src/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
//! v: 0,
//! w: 0,
//! f: 0,
//! t: 0
//! t: 0,
//! c: 0,
//! };
//! ```
//!
Expand Down
15 changes: 15 additions & 0 deletions components/plurals/src/rules/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ impl<'p> Parser<'p> {

fn get_expression(&mut self) -> Result<Option<ast::Expression>, ParserError> {
let operand = match self.lexer.peek() {
Some(Token::E) => ast::Operand::E,
Some(Token::Operand(op)) => *op,
Some(Token::At) | None => return Ok(None),
_ => return Err(ParserError::ExpectedOperand),
Expand Down Expand Up @@ -302,6 +303,20 @@ impl<'p> Parser<'p> {
self.lexer.next();
}
}

if self.take_if(Token::E) {
s.push('e');
match self.lexer.peek() {
Some(Token::Zero) => s.push('0'),
Some(Token::Number(v)) => {
s.push_str(&v.to_string());
}
_ => {
return Err(ParserError::ExpectedValue);
}
}
self.lexer.next();
}
if s.is_empty() {
Err(ParserError::ExpectedValue)
} else {
Expand Down
1 change: 1 addition & 0 deletions components/plurals/src/rules/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ fn calculate_expression(expression: &ast::Expression, operands: &PluralOperands)
ast::Operand::V => operands.v as u64,
ast::Operand::W => operands.w as u64,
ast::Operand::T => operands.t,
ast::Operand::C | ast::Operand::E => operands.c as u64,
};
if let Some(modulus) = &expression.modulus {
value.checked_rem_euclid(modulus.0)
Expand Down
7 changes: 3 additions & 4 deletions components/plurals/src/rules/serializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ fn serialize_operand(operand: ast::Operand, w: &mut impl fmt::Write) -> fmt::Res
ast::Operand::W => w.write_char('w'),
ast::Operand::F => w.write_char('f'),
ast::Operand::T => w.write_char('t'),
ast::Operand::C => w.write_char('c'),
ast::Operand::E => w.write_char('e'),
}
}

Expand All @@ -115,7 +117,7 @@ fn serialize_rangelist(rl: &ast::RangeList, w: &mut impl fmt::Write) -> fmt::Res
if first {
first = false;
} else {
w.write_str(",")?;
w.write_str(", ")?;
}
serialize_rangelistitem(rli, w)?
}
Expand Down Expand Up @@ -144,9 +146,6 @@ pub fn serialize_samples(samples: &ast::Samples, w: &mut impl fmt::Write) -> fmt
if let Some(sample_list) = &samples.integer {
w.write_str(" @integer ")?;
serialize_sample_list(sample_list, w)?;
} else {
// Quirk of the current serializer
w.write_str(" ")?;
}
if let Some(sample_list) = &samples.decimal {
w.write_str(" @decimal ")?;
Expand Down
15 changes: 13 additions & 2 deletions components/plurals/tests/fixtures/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,15 @@ impl From<&FixedDecimalInput> for FixedDecimal {
#[derive(Debug, Clone, Deserialize)]
#[serde(untagged)]
pub enum PluralOperandsInput {
List((f64, u64, usize, usize, u64, u64)),
List((f64, u64, usize, usize, u64, u64, usize)),
Struct {
n: Option<f64>,
i: Option<u64>,
v: Option<usize>,
w: Option<usize>,
f: Option<u64>,
t: Option<u64>,
c: Option<usize>,
},
String(String),
Number(isize),
Expand All @@ -69,13 +70,23 @@ impl From<PluralOperandsInput> for PluralOperands {
w: operands.3,
f: operands.4,
t: operands.5,
c: operands.6,
},
PluralOperandsInput::Struct { n, i, v, w, f, t } => Self {
PluralOperandsInput::Struct {
n,
i,
v,
w,
f,
t,
c,
} => Self {
i: i.unwrap_or_else(|| n.unwrap_or(0_f64) as u64),
v: v.unwrap_or(0),
w: w.unwrap_or(0),
f: f.unwrap_or(0),
t: t.unwrap_or(0),
c: c.unwrap_or(0),
},
PluralOperandsInput::String(num) => num
.parse()
Expand Down
Loading

0 comments on commit 2a9adbc

Please sign in to comment.