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

pomsky-lang / pomsky / 9142134100

18 May 2024 07:23PM UTC coverage: 82.949% (-1.3%) from 84.258%
9142134100

push

github

Aloso
fix e2e tests

1 of 1 new or added line in 1 file covered. (100.0%)

271 existing lines in 24 files now uncovered.

4242 of 5114 relevant lines covered (82.95%)

420176.26 hits per line

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

76.19
/pomsky-syntax/src/exprs/char_class/char_group.rs
1
//! Contains the [`CharGroup`] type, which is the contents of a
2
//! [`CharClass`](crate::char_class::CharClass).
3
//!
4
//! However, a `CharGroup` doesn't store the information whether the character
5
//! class is negated.
6
//!
7
//! Refer to the [`char_class` module](crate::char_class) for more information.
8

9
use crate::error::{DeprecationError, ParseErrorKind};
10

11
use super::unicode::{Category, CodeBlock, OtherProperties, Script};
12

13
/// The contents of a [`CharClass`](crate::char_class::CharClass).
14
///
15
/// Refer to the [`char_class` module](crate::char_class) for more information.
16
#[derive(Clone, PartialEq, Eq)]
17
pub struct CharGroup {
18
    /// This variant is used for the remaining cases.
19
    pub items: Vec<GroupItem>,
20
}
21

22
impl CharGroup {
23
    /// Tries to create a `CharGroup` from a range of characters (inclusive).
24
    /// Returns `None` if `last` is lower than `first`.
25
    pub(crate) fn try_from_range(first: char, last: char) -> Option<Vec<GroupItem>> {
7✔
26
        if first < last {
7✔
27
            Some(vec![GroupItem::Range { first, last }])
6✔
28
        } else {
29
            None
1✔
30
        }
31
    }
7✔
32

33
    /// Try to create a `CharGroup` from the name of a character class. Fails if
34
    /// the name is lowercase and not known, or if it matches a keyword.
35
    ///
36
    /// POSIX classes (e.g. `alnum` or `blank`) are converted to ranges (e.g.
37
    /// `[0-9a-zA-Z]`). This is relatively simple and maximizes
38
    /// compatibility.
39
    ///
40
    /// If the name is uppercase (and not `R`), we just assume that it is a
41
    /// Unicode category, script or block. This needs to be fixed at one
42
    /// point!
43
    pub(crate) fn try_from_group_name(
155✔
44
        name: &str,
155✔
45
        negative: bool,
155✔
46
    ) -> Result<Vec<GroupItem>, ParseErrorKind> {
155✔
47
        Ok(match name {
155✔
48
            _ if name == "ascii" || name.starts_with("ascii_") => {
155✔
49
                super::ascii::parse_ascii_group(name, negative)?
15✔
50
            }
51
            "." => return Err(DeprecationError::DotInSet.into()),
140✔
52
            _ => {
53
                let name = super::unicode::parse_group_name(name)?;
139✔
54
                vec![GroupItem::Named { name, negative }]
138✔
55
            }
56
        })
57
    }
155✔
58
}
59

60
/// One item in a character class.
61
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
62
pub enum GroupItem {
63
    /// A Unicode code point. It can be denoted in quotes (e.g. `'a'`) or in
64
    /// hexadecimal notation (`U+201`).
65
    ///
66
    /// Some non-printable ASCII characters are also parsed to a
67
    /// [`GroupItem::Char`]: `[n]`, `[t]`, `[r]`, `[a]`, `[e]` and `[f]`.
68
    Char(char),
69
    /// A range of Unicode code points. It is denoted as `A-B`, where `A` and
70
    /// `B` are Unicode code points, allowing the same notation as for
71
    /// [`GroupItem::Char`]. Both `A` and `B` are included in the range.
72
    Range { first: char, last: char },
73
    /// A named character class, i.e. a shorthand or a Unicode
74
    /// category/script/block. Shorthands are `[w]`, `[s]`, `[d]`, `[v]`,
75
    /// `[h]` and `[R]`.
76
    ///
77
    /// Some of them (`w`, `d`, `s` and Unicode) can be negated.
78
    Named { name: GroupName, negative: bool },
79
}
80

81
impl GroupItem {
82
    pub(crate) fn range_unchecked(first: char, last: char) -> Self {
23✔
83
        GroupItem::Range { first, last }
23✔
84
    }
23✔
85

86
    #[cfg(feature = "dbg")]
87
    pub(crate) fn pretty_print(&self, buf: &mut crate::PrettyPrinter) {
10✔
88
        fn print_char(c: char, buf: &mut crate::PrettyPrinter) {
10✔
89
            match c {
8✔
90
                '\n' => buf.push('n'),
10✔
91
                '\r' => buf.push('r'),
10✔
92
                '\t' => buf.push('t'),
10✔
93
                '\u{07}' => buf.push('a'),
10✔
94
                '\u{1b}' => buf.push('e'),
10✔
95
                '\u{0c}' => buf.push('f'),
10✔
96
                _ => buf.pretty_print_char(c),
10✔
97
            }
10✔
98
        }
10✔
99

10✔
100
        match *self {
10✔
101
            Self::Char(c) => print_char(c, buf),
6✔
102
            Self::Range { first, last } => {
1✔
103
                print_char(first, buf);
1✔
104
                buf.push('-');
1✔
105
                print_char(last, buf);
1✔
106
            }
1✔
107
            Self::Named { name, negative } => {
3✔
108
                if negative {
3✔
109
                    buf.push('!');
×
110
                }
3✔
111
                let name = match name {
3✔
112
                    GroupName::Word => "word",
1✔
113
                    GroupName::Digit => "digit",
1✔
114
                    GroupName::Space => "space",
1✔
115
                    GroupName::HorizSpace => "horiz_space",
×
116
                    GroupName::VertSpace => "vert_space",
×
117
                    GroupName::Category(c) => c.as_str(),
×
118
                    GroupName::Script(s) => s.as_str(),
×
119
                    GroupName::CodeBlock(b) => b.as_str(),
×
120
                    GroupName::OtherProperties(b) => b.as_str(),
×
121
                };
122
                buf.push_str(name);
3✔
123
            }
124
        }
125
    }
10✔
126
}
127

128
#[cfg(feature = "arbitrary")]
129
impl arbitrary::Arbitrary<'_> for GroupItem {
130
    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
131
        Ok(match u.int_in_range(0u8..=2)? {
132
            0 => GroupItem::Char(u.arbitrary()?),
133
            1 => {
134
                let first = u.arbitrary()?;
135
                let last = u.arbitrary()?;
136
                if first >= last {
137
                    return Err(arbitrary::Error::IncorrectFormat);
138
                }
139
                GroupItem::Range { first, last }
140
            }
141
            _ => GroupItem::Named { name: GroupName::arbitrary(u)?, negative: bool::arbitrary(u)? },
142
        })
143
    }
144

145
    fn size_hint(depth: usize) -> (usize, Option<usize>) {
146
        arbitrary::size_hint::and(
147
            u8::size_hint(depth),
148
            arbitrary::size_hint::or_all(&[
149
                char::size_hint(depth),
150
                arbitrary::size_hint::and(char::size_hint(depth), char::size_hint(depth)),
151
                arbitrary::size_hint::and(GroupName::size_hint(depth), bool::size_hint(depth)),
152
            ]),
153
        )
154
    }
155
}
156

157
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
158
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
159
pub enum GroupName {
160
    Word,
161
    Digit,
162
    Space,
163
    HorizSpace,
164
    VertSpace,
165
    Category(Category),
166
    Script(Script),
167
    CodeBlock(CodeBlock),
168
    OtherProperties(OtherProperties),
169
}
170

171
impl GroupName {
UNCOV
172
    pub fn kind(self) -> &'static str {
×
UNCOV
173
        match self {
×
174
            GroupName::Word
175
            | GroupName::Digit
176
            | GroupName::Space
177
            | GroupName::HorizSpace
UNCOV
178
            | GroupName::VertSpace => "shorthand",
×
UNCOV
179
            GroupName::Category(_) => "category",
×
UNCOV
180
            GroupName::Script(_) => "script",
×
UNCOV
181
            GroupName::CodeBlock(_) => "block",
×
UNCOV
182
            GroupName::OtherProperties(_) => "property",
×
183
        }
UNCOV
184
    }
×
185
}
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