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

pomsky-lang / pomsky / 12099739427

30 Nov 2024 09:51PM UTC coverage: 80.473% (-0.6%) from 81.072%
12099739427

push

github

Aloso
feat: character set intersections

200 of 274 new or added lines in 19 files covered. (72.99%)

3 existing lines in 3 files now uncovered.

4422 of 5495 relevant lines covered (80.47%)

391063.72 hits per line

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

87.2
/pomsky-lib/src/unicode_set.rs
1
use std::{
2
    cmp::Ordering,
3
    collections::BTreeSet,
4
    ops::{Add, AddAssign, RangeInclusive},
5
};
6

7
use pomsky_syntax::exprs::Category;
8

9
use crate::{
10
    exprs::char_class::RegexCharSetItem,
11
    regex::{RegexProperty, RegexShorthand},
12
};
13

14
#[derive(Debug, Default)]
15
pub(crate) struct UnicodeSet {
16
    ranges: BTreeSet<SetRange>,
17
    props: Vec<RegexCharSetItem>,
18
}
19

20
impl From<char> for UnicodeSet {
21
    fn from(value: char) -> Self {
8✔
22
        let mut set = UnicodeSet::new();
8✔
23
        set.ranges.insert(SetRange::single(value as u32));
8✔
24
        set
8✔
25
    }
8✔
26
}
27

28
#[derive(Debug, Eq, Clone, Copy)]
29
pub(crate) struct SetRange {
30
    pub(crate) first: u32,
31
    pub(crate) last: u32,
32
}
33

34
impl SetRange {
35
    pub(crate) fn single(char: u32) -> Self {
1,006✔
36
        SetRange { first: char, last: char }
1,006✔
37
    }
1,006✔
38

39
    pub(crate) fn overlaps_with(&self, other: &SetRange) -> bool {
×
40
        !(self.first > other.last || other.first > self.last)
×
41
    }
×
42

43
    pub(crate) fn as_chars(self) -> (char, char) {
629✔
44
        (self.first.try_into().unwrap(), self.last.try_into().unwrap())
629✔
45
    }
629✔
46
}
47

48
impl PartialEq for SetRange {
49
    fn eq(&self, other: &SetRange) -> bool {
×
50
        self.overlaps_with(other)
×
51
    }
×
52
}
53

54
impl PartialOrd for SetRange {
55
    fn partial_cmp(&self, other: &SetRange) -> Option<Ordering> {
195✔
56
        Some(self.cmp(other))
195✔
57
    }
195✔
58
}
59

60
impl Ord for SetRange {
61
    fn cmp(&self, other: &Self) -> Ordering {
1,233✔
62
        if self.first > other.last {
1,233✔
63
            Ordering::Greater
687✔
64
        } else if other.first > self.last {
546✔
65
            Ordering::Less
430✔
66
        } else {
67
            Ordering::Equal
116✔
68
        }
69
    }
1,233✔
70
}
71

72
impl Add for SetRange {
73
    type Output = SetRange;
74

75
    fn add(self, rhs: SetRange) -> Self::Output {
67✔
76
        SetRange { first: self.first.min(rhs.first), last: self.last.max(rhs.last) }
67✔
77
    }
67✔
78
}
79

80
impl AddAssign for SetRange {
81
    fn add_assign(&mut self, rhs: SetRange) {
67✔
82
        *self = *self + rhs;
67✔
83
    }
67✔
84
}
85

86
impl UnicodeSet {
87
    pub fn new() -> Self {
504✔
88
        UnicodeSet { ranges: BTreeSet::new(), props: Vec::new() }
504✔
89
    }
504✔
90

91
    pub fn try_into_char(&self) -> Option<char> {
251✔
92
        if self.ranges.len() == 1 && self.props.is_empty() {
251✔
93
            let range = self.ranges.first().unwrap();
89✔
94
            if range.first == range.last && range.first != b'\r' as u32 {
89✔
95
                return Some(range.first.try_into().unwrap());
63✔
96
            }
26✔
97
        }
162✔
98
        None
188✔
99
    }
251✔
100

101
    pub fn len(&self) -> usize {
423✔
102
        self.ranges.len() + self.props.len()
423✔
103
    }
423✔
104

105
    pub fn add_char(&mut self, char: char) {
280✔
106
        self.add(SetRange::single(char as u32));
280✔
107
    }
280✔
108

109
    pub fn add_range(&mut self, range: RangeInclusive<char>) {
79✔
110
        self.add(SetRange { first: *range.start() as u32, last: *range.end() as u32 })
79✔
111
    }
79✔
112

113
    pub fn add_set_range(&mut self, range: SetRange) {
×
114
        self.add(range)
×
115
    }
×
116

117
    pub fn add_range_unchecked(&mut self, range: RangeInclusive<char>) {
225✔
118
        self.ranges.insert(SetRange { first: *range.start() as u32, last: *range.end() as u32 });
225✔
119
    }
225✔
120

121
    fn add(&mut self, mut range_new: SetRange) {
359✔
122
        let lower = SetRange::single(range_new.first.saturating_sub(1));
359✔
123
        let upper = SetRange::single(range_new.last.saturating_add(1));
359✔
124

359✔
125
        let overlapping = self.ranges.range(lower..=upper).copied().collect::<MaxTwoArray<_>>();
359✔
126
        for &r in overlapping.iter() {
359✔
127
            range_new += r;
67✔
128
            self.ranges.remove(&r);
67✔
129
        }
67✔
130
        self.ranges.insert(range_new);
359✔
131
    }
359✔
132

133
    pub fn add_prop(&mut self, prop: RegexCharSetItem) {
169✔
134
        if self.props.contains(&prop) {
169✔
135
            return;
1✔
136
        }
168✔
137
        self.props.push(prop);
168✔
138
    }
169✔
139

140
    pub fn full_props(&self) -> Option<(RegexCharSetItem, RegexCharSetItem)> {
50✔
141
        let mut prev_items = vec![];
50✔
142

143
        for &(mut item) in &self.props {
96✔
144
            use RegexCharSetItem as RCS;
46✔
145
            use RegexProperty as RP;
46✔
146
            use RegexShorthand as RS;
46✔
147

148
            if let RCS::Property { negative, value: RP::Category(Category::Separator) } = item {
12✔
149
                item = RCS::Shorthand(if negative { RS::NotSpace } else { RS::Space });
×
150
            }
49✔
151

152
            if let Some(negated) = item.negate() {
49✔
153
                if prev_items.contains(&negated) {
47✔
154
                    return Some((negated, item));
3✔
155
                }
44✔
156
            }
2✔
157

158
            prev_items.push(item);
46✔
159
        }
160

161
        None
47✔
162
    }
50✔
163

164
    pub fn ranges(&self) -> impl '_ + Iterator<Item = SetRange> {
596✔
165
        self.ranges.iter().copied()
596✔
166
    }
596✔
167

168
    pub fn props(&self) -> impl '_ + Iterator<Item = RegexCharSetItem> {
350✔
169
        self.props.iter().copied()
350✔
170
    }
350✔
171

172
    pub(crate) fn extend(&mut self, other: UnicodeSet) {
1✔
173
        for prop in other.props {
2✔
174
            self.add_prop(prop);
1✔
175
        }
1✔
176
        for range in other.ranges {
1✔
NEW
177
            self.add(range);
×
NEW
178
        }
×
179
    }
1✔
180
}
181

182
struct MaxTwoArray<T> {
183
    items: [Option<T>; 2],
184
}
185

186
impl<T> MaxTwoArray<T> {
187
    fn iter(&self) -> impl Iterator<Item = &T> {
359✔
188
        self.items.iter().filter_map(|it| it.as_ref())
718✔
189
    }
359✔
190
}
191

192
impl<A> FromIterator<A> for MaxTwoArray<A> {
193
    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
359✔
194
        let mut iter = iter.into_iter();
359✔
195
        let mut res = MaxTwoArray { items: [const { None }; 2] };
359✔
196

197
        if let Some(item) = iter.next() {
359✔
198
            res.items[0] = Some(item);
67✔
199
            if let Some(item) = iter.next() {
67✔
200
                res.items[1] = Some(item);
×
201
                if iter.next().is_some() {
×
202
                    panic!("Unexpected iterator having more than 2 elements");
×
203
                }
×
204
            }
67✔
205
        }
292✔
206

207
        res
359✔
208
    }
359✔
209
}
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