Skip to content

Commit

Permalink
Add PluralRules Serializer and extend parser to samples. (#206)
Browse files Browse the repository at this point in the history
* Rename parse to parse_condition

* Add Serializer
  • Loading branch information
zbraniecki authored Aug 19, 2020
1 parent 333d83b commit f2d1713
Show file tree
Hide file tree
Showing 11 changed files with 422 additions and 71 deletions.
4 changes: 2 additions & 2 deletions components/pluralrules/benches/pluralrules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion};
use icu_pluralrules::PluralCategory;

fn plurals_bench(c: &mut Criterion) {
use icu_pluralrules::rules::{parse, Lexer};
use icu_pluralrules::rules::{parse_condition, Lexer};

let path = "./benches/fixtures/plurals.json";
let data: fixtures::PluralsFixture =
Expand Down Expand Up @@ -34,7 +34,7 @@ fn plurals_bench(c: &mut Criterion) {
group.bench_function("parse", |b| {
b.iter(|| {
for val in &pl_data {
let _ = parse(black_box(val.as_bytes()));
let _ = parse_condition(black_box(val.as_bytes()));
}
})
});
Expand Down
4 changes: 2 additions & 2 deletions components/pluralrules/src/data/io/bincode/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::data::cldr_resource::Resource;
use crate::data::provider::{DataProviderError, DataProviderType};
use crate::data::{PluralRuleList, RulesSelector};
use crate::rules::parse;
use crate::rules::parse_condition;
use crate::PluralCategory;
use crate::PluralRuleType;
use icu_locale::LanguageIdentifier;
Expand Down Expand Up @@ -89,7 +89,7 @@ pub fn get_rules(
let result = PluralCategory::all()
.filter_map(|pc| {
let input = lang_rules.get(pc)?;
Some(parse(input.as_bytes()).map(|ast| (*pc, ast)))
Some(parse_condition(input.as_bytes()).map(|ast| (*pc, ast)))
})
.collect::<Result<_, _>>()?;

Expand Down
4 changes: 2 additions & 2 deletions components/pluralrules/src/data/io/json/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::data::cldr_resource::Resource;
use crate::data::provider::{DataProviderError, DataProviderType};
use crate::data::{PluralRuleList, RulesSelector};
use crate::rules::parse;
use crate::rules::parse_condition;
use crate::PluralCategory;
use crate::PluralRuleType;
use icu_locale::LanguageIdentifier;
Expand Down Expand Up @@ -88,7 +88,7 @@ pub fn get_rules(
let result = PluralCategory::all()
.filter_map(|pc| {
let input = lang_rules.get(pc)?;
Some(parse(input.as_bytes()).map(|ast| (*pc, ast)))
Some(parse_condition(input.as_bytes()).map(|ast| (*pc, ast)))
})
.collect::<Result<_, _>>()?;

Expand Down
4 changes: 2 additions & 2 deletions components/pluralrules/src/data/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
//! use icu_pluralrules::rules::ast;
//! use icu_locale::LanguageIdentifier;
//!
//! use icu_pluralrules::rules::parse;
//! use icu_pluralrules::rules::parse_condition;
//!
//! struct MyDataProvider {}
//!
Expand All @@ -39,7 +39,7 @@
//!
//! let conditions: Vec<(PluralCategory, ast::Condition)> =
//! sources.iter().map(|(category, rule_str)| {
//! let condition = parse(rule_str.as_bytes())
//! let condition = parse_condition(rule_str.as_bytes())
//! .expect("Failed to parse the plural rule.");
//! (*category, condition)
//! }).collect();
Expand Down
96 changes: 56 additions & 40 deletions components/pluralrules/src/rules/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
//! # Examples
//!
//! ```
//! use icu_pluralrules::rules::parse;
//! use icu_pluralrules::rules::parse_condition;
//! use icu_pluralrules::rules::ast::*;
//!
//! let input = "i = 1";
//!
//! let ast = parse(input.as_bytes())
//! let ast = parse_condition(input.as_bytes())
//! .expect("Parsing failed.");
//!
//! assert_eq!(ast, Condition(Box::new([
Expand All @@ -36,19 +36,59 @@
//! [`test_condition`]: ../fn.test_condition.html
use std::ops::RangeInclusive;

/// A complete AST representation of a plural rule.
/// Comprises a vector of AndConditions and optionally a set of Samples.
///
/// # Examples
///
/// ```
/// use icu_pluralrules::rules::ast::*;
/// use icu_pluralrules::rules::{parse, parse_condition};
///
/// let condition = parse_condition(b"i = 5 or v = 2")
/// .expect("Parsing failed.");
///
/// let samples = Samples {
/// integer: Some(SampleList {
/// sample_ranges: Box::new([SampleRange {
/// lower_val: DecimalValue("2".to_string()),
/// upper_val: None,
/// }]),
/// ellipsis: true
/// }),
/// decimal: Some(SampleList {
/// sample_ranges: Box::new([SampleRange {
/// lower_val: DecimalValue("2.5".to_string()),
/// upper_val: None,
/// }]),
/// ellipsis: false
/// }),
/// };
///
/// let rule = Rule {
/// condition,
/// samples: Some(samples),
/// };
///
/// assert_eq!(
/// rule,
/// parse("i = 5 or v = 2 @integer 2, … @decimal 2.5".as_bytes())
/// .expect("Parsing failed")
/// )
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Rule {
pub condition: Condition,
pub samples: Option<Samples>,
}

/// A complete (and the only complete) AST representation of a plural rule. Comprises a vector of AndConditions.
/// A complete AST representation of a plural rule's condition. Comprises a vector of AndConditions.
///
/// # Examples
///
/// ```
/// use icu_pluralrules::rules::ast::*;
/// use icu_pluralrules::rules::parse;
/// use icu_pluralrules::rules::parse_condition;
///
/// let condition = Condition(Box::new([
/// AndCondition(Box::new([Relation {
Expand All @@ -71,7 +111,7 @@ pub struct Rule {
///
/// assert_eq!(
/// condition,
/// parse(b"i = 5 or v = 2")
/// parse_condition(b"i = 5 or v = 2")
/// .expect("Parsing failed")
/// )
/// ```
Expand Down Expand Up @@ -157,7 +197,7 @@ pub struct Relation {
/// | Eq | "=" |
/// | NotEq | "!=" |
///
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Operator {
Eq,
NotEq,
Expand Down Expand Up @@ -207,7 +247,7 @@ pub struct Expression {
///
/// Operand::I;
/// ```
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Operand {
/// Absolute value of input
N,
Expand Down Expand Up @@ -306,20 +346,14 @@ pub struct Value(pub u64);
/// Samples {
/// integer: Some(SampleList {
/// sample_ranges: Box::new([SampleRange {
/// lower_val: DecimalValue {
/// integer: Value(2),
/// decimal: None
/// },
/// lower_val: DecimalValue("2".to_string()),
/// upper_val: None,
/// }]),
/// ellipsis: true
/// }),
/// decimal: Some(SampleList {
/// sample_ranges: Box::new([SampleRange {
/// lower_val: DecimalValue {
/// integer: Value(2),
/// decimal: Some(Value(5))
/// },
/// lower_val: DecimalValue("2.5".to_string()),
/// upper_val: None,
/// }]),
/// ellipsis: false
Expand All @@ -345,14 +379,8 @@ pub struct Samples {
/// SampleList {
/// sample_ranges: Box::new([
/// SampleRange {
/// lower_val: DecimalValue {
/// integer: Value(0),
/// decimal: Some(Value(0)),
/// },
/// upper_val: Some(DecimalValue {
/// integer: Value(1),
/// decimal: Some(Value(5)),
/// }),
/// lower_val: DecimalValue("0.0".to_string()),
/// upper_val: Some(DecimalValue("1.5".to_string())),
/// }
/// ]),
/// ellipsis: true
Expand All @@ -375,14 +403,8 @@ pub struct SampleList {
/// ```
/// use icu_pluralrules::rules::ast::*;
/// SampleRange {
/// lower_val: DecimalValue {
/// integer: Value(0),
/// decimal: Some(Value(0)),
/// },
/// upper_val: Some(DecimalValue {
/// integer: Value(1),
/// decimal: Some(Value(5)),
/// }),
/// lower_val: DecimalValue("0.0".to_string()),
/// upper_val: Some(DecimalValue("1.5".to_string())),
/// };
/// ```
#[derive(Debug, Clone, PartialEq)]
Expand All @@ -396,18 +418,12 @@ pub struct SampleRange {
/// # Examples
///
/// ```text
/// 1.5
/// 1.00
/// ```
///
/// ```
/// use icu_pluralrules::rules::ast::*;
/// DecimalValue {
/// integer: Value(1),
/// decimal: Some(Value(5)),
/// };
/// DecimalValue("1.00".to_string());
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct DecimalValue {
pub integer: Value,
pub decimal: Option<Value>,
}
pub struct DecimalValue(pub String);
6 changes: 4 additions & 2 deletions components/pluralrules/src/rules/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ pub enum Token {
Operand(ast::Operand),
Operator(ast::Operator),
Number(u32),
Zero,
Dot,
DotDot,
DotDotDot,
Comma,
Or,
And,
Expand Down Expand Up @@ -106,7 +106,9 @@ impl<'l> Lexer<'l> {
b'v' => Token::Operand(ast::Operand::V),
b'w' => Token::Operand(ast::Operand::W),
b'=' => Token::Operator(ast::Operator::Eq),
b'0'..=b'9' => {
// Zero is special, because we need to preserve it for Samples.
b'0' => Token::Zero,
b'1'..=b'9' => {
let start = self.ptr - 1;

while let Some(b'0'..=b'9') = self.chars.get(self.ptr) {
Expand Down
12 changes: 7 additions & 5 deletions components/pluralrules/src/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@
//! When parsed, the resulting [`AST`] will look like this:
//!
//! ```
//! use icu_pluralrules::rules::parse;
//! use icu_pluralrules::rules::parse_condition;
//! use icu_pluralrules::rules::ast::*;
//!
//! let input = "i = 1 and v = 0 @integer 1";
//!
//! let ast = parse(input.as_bytes())
//! let ast = parse_condition(input.as_bytes())
//! .expect("Parsing failed.");
//! assert_eq!(ast, Condition(Box::new([
//! AndCondition(Box::new([
Expand Down Expand Up @@ -91,14 +91,14 @@
//! matches:
//!
//! ```
//! use icu_pluralrules::rules::{test_condition, parse};
//! use icu_pluralrules::rules::{test_condition, parse_condition};
//! use icu_pluralrules::PluralOperands;
//!
//! let input = "i = 1 and v = 0 @integer 1";
//!
//! let operands = PluralOperands::from(1_u32);
//!
//! let ast = parse(input.as_bytes())
//! let ast = parse_condition(input.as_bytes())
//! .expect("Parsing failed.");
//!
//! assert!(test_condition(&ast, &operands));
Expand Down Expand Up @@ -141,7 +141,9 @@ pub mod ast;
pub(crate) mod lexer;
pub(crate) mod parser;
pub(crate) mod resolver;
pub(crate) mod serializer;

pub use lexer::Lexer;
pub use parser::parse;
pub use parser::{parse, parse_condition};
pub use resolver::test_condition;
pub use serializer::serialize;
Loading

0 comments on commit f2d1713

Please sign in to comment.