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

projectfluent / fluent-rs / 3758849996

pending completion
3758849996

push

github

GitHub
Apply cargo fmt and clippy (#308)

18 of 18 new or added lines in 3 files covered. (100.0%)

4004 of 4458 relevant lines covered (89.82%)

2655.71 hits per line

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

99.24
/fluent-syntax/src/parser/pattern.rs
1
use super::errors::{ErrorKind, ParserError};
2
use super::{core::Parser, core::Result, slice::Slice};
3
use crate::ast;
4

5
#[derive(Debug, PartialEq)]
6
enum TextElementTermination {
7
    LineFeed,
8
    Crlf,
9
    PlaceableStart,
10
    Eof,
11
}
12

13
// This enum tracks the placement of the text element in the pattern, which is needed for
14
// dedentation logic.
15
#[derive(Debug, PartialEq)]
16
enum TextElementPosition {
17
    InitialLineStart,
18
    LineStart,
19
    Continuation,
20
}
21

22
// This enum allows us to mark pointers in the source which will later become text elements
23
// but without slicing them out of the source string. This makes the indentation adjustments
24
// cheaper since they'll happen on the pointers, rather than extracted slices.
25
#[derive(Debug)]
26
enum PatternElementPlaceholders<S> {
27
    Placeable(ast::Expression<S>),
28
    // (start, end, indent, position)
29
    TextElement(usize, usize, usize, TextElementPosition),
30
}
31

32
// This enum tracks whether the text element is blank or not.
33
// This is important to identify text elements which should not be taken into account
34
// when calculating common indent.
35
#[derive(Debug, PartialEq)]
36
enum TextElementType {
37
    Blank,
38
    NonBlank,
39
}
40

41
impl<'s, S> Parser<S>
42
where
43
    S: Slice<'s>,
44
{
45
    pub(super) fn get_pattern(&mut self) -> Result<Option<ast::Pattern<S>>> {
24,199✔
46
        let mut elements = vec![];
24,199✔
47
        let mut last_non_blank = None;
24,199✔
48
        let mut common_indent = None;
24,199✔
49

24,199✔
50
        self.skip_blank_inline();
24,199✔
51

52
        let mut text_element_role = if self.skip_eol() {
24,199✔
53
            self.skip_blank_block();
3,058✔
54
            TextElementPosition::LineStart
3,058✔
55
        } else {
56
            TextElementPosition::InitialLineStart
21,141✔
57
        };
58

59
        while self.ptr < self.length {
61,640✔
60
            if self.take_byte_if(b'{') {
59,687✔
61
                if text_element_role == TextElementPosition::LineStart {
12,504✔
62
                    common_indent = Some(0);
30✔
63
                }
12,474✔
64
                let exp = self.get_placeable()?;
12,504✔
65
                last_non_blank = Some(elements.len());
12,057✔
66
                elements.push(PatternElementPlaceholders::Placeable(exp));
12,057✔
67
                text_element_role = TextElementPosition::Continuation;
12,057✔
68
            } else {
69
                let slice_start = self.ptr;
47,183✔
70
                let mut indent = 0;
47,183✔
71
                if text_element_role == TextElementPosition::LineStart {
47,183✔
72
                    indent = self.skip_blank_inline();
24,982✔
73
                    if let Some(b) = get_current_byte!(self) {
24,982✔
74
                        if indent == 0 {
24,946✔
75
                            if b != &b'\r' && b != &b'\n' {
17,857✔
76
                                break;
15,101✔
77
                            }
2,758✔
78
                        } else if !Self::is_byte_pattern_continuation(*b) {
7,089✔
79
                            self.ptr = slice_start;
6,658✔
80
                            break;
6,658✔
81
                        }
429✔
82
                    } else {
83
                        break;
36✔
84
                    }
85
                }
22,201✔
86
                let (start, end, text_element_type, termination_reason) = self.get_text_slice()?;
25,388✔
87
                if start != end {
25,376✔
88
                    if text_element_role == TextElementPosition::LineStart
25,118✔
89
                        && text_element_type == TextElementType::NonBlank
2,920✔
90
                    {
91
                        if let Some(common) = common_indent {
141✔
92
                            if indent < common {
62✔
93
                                common_indent = Some(indent);
10✔
94
                            }
52✔
95
                        } else {
79✔
96
                            common_indent = Some(indent);
79✔
97
                        }
79✔
98
                    }
24,977✔
99
                    if text_element_role != TextElementPosition::LineStart
25,118✔
100
                        || text_element_type == TextElementType::NonBlank
2,920✔
101
                        || termination_reason == TextElementTermination::LineFeed
2,779✔
102
                    {
103
                        if text_element_type == TextElementType::NonBlank {
25,118✔
104
                            last_non_blank = Some(elements.len());
12,958✔
105
                        }
14,256✔
106
                        elements.push(PatternElementPlaceholders::TextElement(
25,109✔
107
                            slice_start,
25,109✔
108
                            end,
25,109✔
109
                            indent,
25,109✔
110
                            text_element_role,
25,109✔
111
                        ));
25,109✔
112
                    }
×
113
                }
258✔
114

115
                text_element_role = match termination_reason {
25,367✔
116
                    TextElementTermination::LineFeed => TextElementPosition::LineStart,
22,402✔
117
                    TextElementTermination::Crlf => TextElementPosition::LineStart,
12✔
118
                    TextElementTermination::PlaceableStart => TextElementPosition::Continuation,
2,760✔
119
                    TextElementTermination::Eof => TextElementPosition::Continuation,
210✔
120
                };
121
            }
122
        }
123

124
        if let Some(last_non_blank) = last_non_blank {
23,748✔
125
            let elements = elements
21,020✔
126
                .into_iter()
21,020✔
127
                .take(last_non_blank + 1)
21,020✔
128
                .enumerate()
21,020✔
129
                .map(|(i, elem)| match elem {
30,204✔
130
                    PatternElementPlaceholders::Placeable(expression) => {
14,453✔
131
                        ast::PatternElement::Placeable { expression }
14,453✔
132
                    }
133
                    PatternElementPlaceholders::TextElement(start, end, indent, role) => {
15,751✔
134
                        let start = if role == TextElementPosition::LineStart {
15,751✔
135
                            common_indent.map_or_else(
191✔
136
                                || start + indent,
191✔
137
                                |common_indent| start + std::cmp::min(indent, common_indent),
191✔
138
                            )
191✔
139
                        } else {
140
                            start
15,560✔
141
                        };
142
                        let mut value = self.source.slice(start..end);
15,751✔
143
                        if last_non_blank == i {
15,751✔
144
                            value.trim();
12,620✔
145
                        }
12,620✔
146
                        ast::PatternElement::TextElement { value }
15,751✔
147
                    }
148
                })
30,204✔
149
                .collect();
21,020✔
150
            return Ok(Some(ast::Pattern { elements }));
21,020✔
151
        }
2,728✔
152

2,728✔
153
        Ok(None)
2,728✔
154
    }
24,208✔
155

156
    fn get_text_slice(
25,386✔
157
        &mut self,
25,386✔
158
    ) -> Result<(usize, usize, TextElementType, TextElementTermination)> {
25,386✔
159
        let start_pos = self.ptr;
25,386✔
160
        let mut text_element_type = TextElementType::Blank;
25,386✔
161

162
        while let Some(b) = get_current_byte!(self) {
168,115✔
163
            match b {
20✔
164
                b' ' => self.ptr += 1,
17,177✔
165
                b'\n' => {
166
                    self.ptr += 1;
22,384✔
167
                    return Ok((
22,384✔
168
                        start_pos,
22,384✔
169
                        self.ptr,
22,384✔
170
                        text_element_type,
22,384✔
171
                        TextElementTermination::LineFeed,
22,384✔
172
                    ));
22,384✔
173
                }
174
                b'\r' if self.is_byte_at(b'\n', self.ptr + 1) => {
21✔
175
                    self.ptr += 1;
12✔
176
                    return Ok((
12✔
177
                        start_pos,
12✔
178
                        self.ptr - 1,
12✔
179
                        text_element_type,
12✔
180
                        TextElementTermination::Crlf,
12✔
181
                    ));
12✔
182
                }
183
                b'{' => {
184
                    return Ok((
2,760✔
185
                        start_pos,
2,760✔
186
                        self.ptr,
2,760✔
187
                        text_element_type,
2,760✔
188
                        TextElementTermination::PlaceableStart,
2,760✔
189
                    ));
2,760✔
190
                }
191
                b'}' => {
192
                    return error!(ErrorKind::UnbalancedClosingBrace, self.ptr);
12✔
193
                }
194
                _ => {
195
                    text_element_type = TextElementType::NonBlank;
125,552✔
196
                    self.ptr += 1
125,552✔
197
                }
198
            }
199
        }
200
        Ok((
210✔
201
            start_pos,
210✔
202
            self.ptr,
210✔
203
            text_element_type,
210✔
204
            TextElementTermination::Eof,
210✔
205
        ))
210✔
206
    }
25,378✔
207
}
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

© 2026 Coveralls, Inc