• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zbraniecki / icu4x / 6815798908

09 Nov 2023 05:17PM UTC coverage: 72.607% (-2.4%) from 75.01%
6815798908

push

github

web-flow
Implement `Any/BufferProvider` for some smart pointers (#4255)

Allows storing them as a `Box<dyn Any/BufferProvider>` without using a
wrapper type that implements the trait.

44281 of 60987 relevant lines covered (72.61%)

201375.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.57
/components/plurals/src/rules/reference/parser.rs
1
// This file is part of ICU4X. For terms of use, please see the file
18✔
2
// called LICENSE at the top level of the ICU4X source tree
3
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4

5
use super::ast;
6
use super::lexer::{Lexer, Token};
7
use alloc::string::String;
8
use alloc::string::ToString;
9
use alloc::vec;
10
use alloc::vec::Vec;
11
use core::iter::Peekable;
12
use displaydoc::Display;
13

14
#[derive(Display, Debug, PartialEq, Eq, Copy, Clone)]
6✔
15
#[allow(clippy::enum_variant_names)]
16
#[non_exhaustive]
17
pub enum ParserError {
18
    #[displaydoc("expected 'AND' condition")]
19
    ExpectedAndCondition,
20
    #[displaydoc("expected relation")]
21
    ExpectedRelation,
22
    #[displaydoc("expected operator")]
23
    ExpectedOperator,
24
    #[displaydoc("expected operand")]
25
    ExpectedOperand,
26
    #[displaydoc("expected value")]
27
    ExpectedValue,
28
    #[displaydoc("expected sample type")]
29
    ExpectedSampleType,
30
    #[displaydoc("Value too large")]
31
    ValueTooLarge,
32
}
33

34
#[cfg(feature = "std")]
35
impl std::error::Error for ParserError {}
36

37
/// Unicode Plural Rule parser converts an
38
/// input string into a Rule [`AST`].
39
///
40
/// A single [`Rule`] contains a [`Condition`] and optionally a set of
41
/// [`Samples`].
42
///
43
/// A [`Condition`] can be then used by the [`test_condition`] to test
44
/// against [`PluralOperands`], to find the appropriate [`PluralCategory`].
45
///
46
/// [`Samples`] are useful for tooling to help translators understand examples of numbers
47
/// covered by the given [`Rule`].
48
///
49
/// At runtime, only the [`Condition`] is used and for that, consider using [`parse_condition`].
50
///
51
/// # Examples
52
///
53
/// ```
54
/// use icu::plurals::rules::reference::parse;
55
///
56
/// let input = b"i = 0 or n = 1 @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04";
57
/// assert!(parse(input).is_ok());
58
/// ```
59
///
60
/// [`AST`]: super::ast
61
/// [`test_condition`]: super::test_condition
62
/// [`PluralOperands`]: crate::PluralOperands
63
/// [`PluralCategory`]: crate::PluralCategory
64
/// [`Rule`]: super::ast::Rule
65
/// [`Samples`]: super::ast::Samples
66
/// [`Condition`]:  super::ast::Condition
67
/// [`parse_condition`]: parse_condition()
68
pub fn parse(input: &[u8]) -> Result<ast::Rule, ParserError> {
35✔
69
    let parser = Parser::new(input);
35✔
70
    parser.parse()
35✔
71
}
35✔
72

73
/// Unicode Plural Rule parser converts an
74
/// input string into an [`AST`].
75
///
76
/// That [`AST`] can be then used by the [`test_condition`] to test
77
/// against [`PluralOperands`], to find the appropriate [`PluralCategory`].
78
///
79
/// # Examples
80
///
81
/// ```
82
/// use icu::plurals::rules::reference::parse_condition;
83
///
84
/// let input = b"i = 0 or n = 1";
85
/// assert!(parse_condition(input).is_ok());
86
/// ```
87
///
88
/// [`AST`]: super::ast
89
/// [`test_condition`]: super::test_condition
90
/// [`PluralOperands`]: crate::PluralOperands
91
/// [`PluralCategory`]: crate::PluralCategory
92
pub fn parse_condition(input: &[u8]) -> Result<ast::Condition, ParserError> {
24✔
93
    let parser = Parser::new(input);
24✔
94
    parser.parse_condition()
24✔
95
}
24✔
96

97
struct Parser<'p> {
98
    lexer: Peekable<Lexer<'p>>,
99
}
100

101
impl<'p> Parser<'p> {
102
    fn new(input: &'p [u8]) -> Self {
59✔
103
        Self {
59✔
104
            lexer: Lexer::new(input).peekable(),
59✔
105
        }
106
    }
59✔
107

108
    pub fn parse(mut self) -> Result<ast::Rule, ParserError> {
35✔
109
        self.get_rule()
35✔
110
    }
35✔
111

112
    pub fn parse_condition(mut self) -> Result<ast::Condition, ParserError> {
24✔
113
        self.get_condition()
24✔
114
    }
24✔
115

116
    fn get_rule(&mut self) -> Result<ast::Rule, ParserError> {
35✔
117
        Ok(ast::Rule {
29✔
118
            condition: self.get_condition()?,
35✔
119
            samples: self.get_samples()?,
29✔
120
        })
×
121
    }
35✔
122

123
    fn get_condition(&mut self) -> Result<ast::Condition, ParserError> {
61✔
124
        let mut result = vec![];
61✔
125

126
        if let Some(cond) = self.get_and_condition()? {
61✔
127
            result.push(cond);
52✔
128
        } else {
129
            return Ok(ast::Condition(result));
2✔
130
        }
2✔
131

132
        while self.take_if(Token::Or) {
68✔
133
            if let Some(cond) = self.get_and_condition()? {
16✔
134
                result.push(cond);
16✔
135
            } else {
136
                return Err(ParserError::ExpectedAndCondition);
1✔
137
            }
138
        }
1✔
139
        // If lexer is not done, error?
140
        Ok(ast::Condition(result))
51✔
141
    }
59✔
142

143
    fn get_and_condition(&mut self) -> Result<Option<ast::AndCondition>, ParserError> {
76✔
144
        if let Some(relation) = self.get_relation()? {
144✔
145
            let mut rel = vec![relation];
69✔
146

147
            while self.take_if(Token::And) {
105✔
148
                if let Some(relation) = self.get_relation()? {
37✔
149
                    rel.push(relation);
36✔
150
                } else {
151
                    return Err(ParserError::ExpectedRelation);
1✔
152
                }
153
            }
1✔
154
            Ok(Some(ast::AndCondition(rel)))
68✔
155
        } else {
69✔
156
            Ok(None)
3✔
157
        }
158
    }
76✔
159

160
    fn get_relation(&mut self) -> Result<Option<ast::Relation>, ParserError> {
113✔
161
        if let Some(expression) = self.get_expression()? {
218✔
162
            let operator = match self.lexer.next() {
108✔
163
                Some(Token::Operator(op)) => op,
106✔
164
                _ => return Err(ParserError::ExpectedOperator),
2✔
165
            };
166
            let range_list = self.get_range_list()?;
106✔
167
            Ok(Some(ast::Relation {
105✔
168
                expression,
105✔
169
                operator,
170
                range_list,
105✔
171
            }))
172
        } else {
173
            Ok(None)
4✔
174
        }
175
    }
113✔
176

177
    fn get_expression(&mut self) -> Result<Option<ast::Expression>, ParserError> {
113✔
178
        let operand = match self.lexer.peek() {
113✔
179
            Some(Token::E) => ast::Operand::E,
4✔
180
            Some(Token::Operand(op)) => *op,
104✔
181
            Some(Token::At) | None => return Ok(None),
4✔
182
            _ => return Err(ParserError::ExpectedOperand),
1✔
183
        };
184
        self.lexer.next();
108✔
185
        let modulus = if self.take_if(Token::Modulo) {
136✔
186
            Some(self.get_value()?)
28✔
187
        } else {
188
            None
80✔
189
        };
190
        Ok(Some(ast::Expression { operand, modulus }))
108✔
191
    }
113✔
192

193
    fn get_range_list(&mut self) -> Result<ast::RangeList, ParserError> {
108✔
194
        let mut range_list = Vec::with_capacity(1);
108✔
195
        loop {
196
            range_list.push(self.get_range_list_item()?);
128✔
197
            if !self.take_if(Token::Comma) {
124✔
198
                break;
199
            }
200
        }
201
        Ok(ast::RangeList(range_list))
105✔
202
    }
106✔
203

204
    fn take_if(&mut self, token: Token) -> bool {
820✔
205
        if self.lexer.peek() == Some(&token) {
820✔
206
            self.lexer.next();
248✔
207
            true
248✔
208
        } else {
209
            false
572✔
210
        }
211
    }
820✔
212

213
    fn get_range_list_item(&mut self) -> Result<ast::RangeListItem, ParserError> {
126✔
214
        let value = self.get_value()?;
126✔
215
        if self.take_if(Token::DotDot) {
148✔
216
            let value2 = self.get_value()?;
23✔
217
            Ok(ast::RangeListItem::Range(value..=value2))
23✔
218
        } else {
219
            Ok(ast::RangeListItem::Value(value))
102✔
220
        }
221
    }
126✔
222

223
    fn get_value(&mut self) -> Result<ast::Value, ParserError> {
176✔
224
        match self.lexer.next() {
176✔
225
            Some(Token::Number(v)) => Ok(ast::Value(v as u64)),
128✔
226
            Some(Token::Zero) => Ok(ast::Value(0)),
47✔
227
            _ => Err(ParserError::ExpectedValue),
1✔
228
        }
229
    }
176✔
230

231
    fn get_samples(&mut self) -> Result<Option<ast::Samples>, ParserError> {
29✔
232
        let mut integer = None;
29✔
233
        let mut decimal = None;
29✔
234

235
        while self.take_if(Token::At) {
44✔
236
            match self.lexer.next() {
15✔
237
                Some(Token::Integer) => integer = Some(self.get_sample_list()?),
8✔
238
                Some(Token::Decimal) => decimal = Some(self.get_sample_list()?),
7✔
239
                _ => return Err(ParserError::ExpectedSampleType),
×
240
            };
241
        }
242
        if integer.is_some() || decimal.is_some() {
29✔
243
            Ok(Some(ast::Samples { integer, decimal }))
9✔
244
        } else {
245
            Ok(None)
20✔
246
        }
247
    }
29✔
248

249
    fn get_sample_list(&mut self) -> Result<ast::SampleList, ParserError> {
15✔
250
        let mut ranges = vec![self.get_sample_range()?];
15✔
251
        let mut ellipsis = false;
15✔
252

253
        while self.take_if(Token::Comma) {
48✔
254
            if self.take_if(Token::Ellipsis) {
40✔
255
                ellipsis = true;
7✔
256
                break;
257
            }
258
            ranges.push(self.get_sample_range()?);
33✔
259
        }
260
        Ok(ast::SampleList {
15✔
261
            sample_ranges: ranges,
15✔
262
            ellipsis,
15✔
263
        })
264
    }
15✔
265

266
    fn get_sample_range(&mut self) -> Result<ast::SampleRange, ParserError> {
48✔
267
        let lower_val = self.get_decimal_value()?;
48✔
268
        let upper_val = if self.take_if(Token::Tilde) {
55✔
269
            Some(self.get_decimal_value()?)
7✔
270
        } else {
×
271
            None
41✔
272
        };
273
        Ok(ast::SampleRange {
48✔
274
            lower_val,
48✔
275
            upper_val,
48✔
276
        })
277
    }
48✔
278

279
    fn get_decimal_value(&mut self) -> Result<ast::DecimalValue, ParserError> {
231✔
280
        let mut s = String::new();
231✔
281
        loop {
282
            match self.lexer.peek() {
286✔
283
                Some(Token::Zero) => s.push('0'),
9✔
284
                Some(Token::Number(v)) => {
46✔
285
                    s.push_str(&v.to_string());
46✔
286
                }
287
                _ => {
288
                    break;
289
                }
290
            }
291
            self.lexer.next();
9✔
292
        }
293
        if self.take_if(Token::Dot) {
55✔
294
            s.push('.');
31✔
295
            loop {
296
                match self.lexer.peek() {
102✔
297
                    Some(Token::Zero) => s.push('0'),
53✔
298
                    Some(Token::Number(v)) => {
18✔
299
                        s.push_str(&v.to_string());
18✔
300
                    }
301
                    _ => {
302
                        break;
303
                    }
304
                }
305
                self.lexer.next();
53✔
306
            }
307
        }
308

309
        if self.take_if(Token::E) {
55✔
310
            s.push('e');
24✔
311
            match self.lexer.peek() {
24✔
312
                Some(Token::Zero) => s.push('0'),
×
313
                Some(Token::Number(v)) => {
24✔
314
                    s.push_str(&v.to_string());
24✔
315
                }
316
                _ => {
317
                    return Err(ParserError::ExpectedValue);
×
318
                }
319
            }
320
            self.lexer.next();
×
321
        }
322
        if s.is_empty() {
55✔
323
            Err(ParserError::ExpectedValue)
×
324
        } else {
325
            Ok(ast::DecimalValue(s))
55✔
326
        }
327
    }
55✔
328
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc