swc_ecma_regexp/parser/pattern_parser/
character.rs

1// ```
2// SyntaxCharacter :: one of
3//   ^ $ \ . * + ? ( ) [ ] { } |
4// ```
5pub fn is_syntax_character(cp: u32) -> bool {
6    char::from_u32(cp).is_some_and(|ch| {
7        matches!(
8            ch,
9            '^' | '$' | '\\' | '.' | '*' | '+' | '?' | '(' | ')' | '[' | ']' | '{' | '}' | '|'
10        )
11    })
12}
13
14// ```
15// ClassSetSyntaxCharacter :: one of
16//   ( ) [ ] { } / - \ |
17// ```
18pub fn is_class_set_syntax_character(cp: u32) -> bool {
19    char::from_u32(cp).is_some_and(|ch| {
20        matches!(
21            ch,
22            '(' | ')' | '[' | ']' | '{' | '}' | '/' | '-' | '\\' | '|'
23        )
24    })
25}
26
27// ```
28// ClassSetReservedDoublePunctuator :: one of
29//   && !! ## $$ %% ** ++ ,, .. :: ;; << == >> ?? @@ ^^ `` ~~
30// ```
31pub fn is_class_set_reserved_double_punctuator(cp1: u32, cp2: u32) -> bool {
32    char::from_u32(cp1).is_some_and(|ch1| {
33        char::from_u32(cp2).is_some_and(|ch2| {
34            matches!(
35                (ch1, ch2),
36                ('&', '&')
37                    | ('!', '!')
38                    | ('#', '#')
39                    | ('$', '$')
40                    | ('%', '%')
41                    | ('*', '*')
42                    | ('+', '+')
43                    | (',', ',')
44                    | ('.', '.')
45                    | (':', ':')
46                    | (';', ';')
47                    | ('<', '<')
48                    | ('=', '=')
49                    | ('>', '>')
50                    | ('?', '?')
51                    | ('@', '@')
52                    | ('^', '^')
53                    | ('`', '`')
54                    | ('~', '~')
55            )
56        })
57    })
58}
59
60// ```
61// ClassSetReservedPunctuator :: one of
62//   & - ! # % , : ; < = > @ ` ~
63// ```
64pub fn is_class_set_reserved_punctuator(cp: u32) -> bool {
65    char::from_u32(cp).is_some_and(|ch| {
66        matches!(
67            ch,
68            '&' | '-' | '!' | '#' | '%' | ',' | ':' | ';' | '<' | '=' | '>' | '@' | '`' | '~'
69        )
70    })
71}
72
73pub fn is_decimal_digit(cp: u32) -> bool {
74    char::from_u32(cp).is_some_and(|ch| ch.is_ascii_digit())
75}
76
77pub fn is_octal_digit(cp: u32) -> bool {
78    char::from_u32(cp).is_some_and(|ch| ch.is_ascii_digit() && ch < '8')
79}
80
81pub fn is_valid_unicode(cp: u32) -> bool {
82    (0..=0x0010_ffff).contains(&cp)
83}
84
85// ```
86// UnicodePropertyNameCharacter ::
87//   AsciiLetter
88//   _
89// ```
90pub fn is_unicode_property_name_character(cp: u32) -> bool {
91    char::from_u32(cp).is_some_and(|ch| ch.is_ascii_alphabetic() || ch == '_')
92}
93
94// ```
95// UnicodePropertyValueCharacter ::
96//   UnicodePropertyNameCharacter
97//   DecimalDigit
98// ```
99pub fn is_unicode_property_value_character(cp: u32) -> bool {
100    char::from_u32(cp).is_some_and(|ch| ch.is_ascii_alphanumeric() || ch == '_')
101}
102
103pub fn is_unicode_id_start(cp: u32) -> bool {
104    char::from_u32(cp).is_some_and(unicode_id_start::is_id_start)
105}
106
107pub fn is_unicode_id_continue(cp: u32) -> bool {
108    char::from_u32(cp).is_some_and(unicode_id_start::is_id_continue)
109}
110
111pub fn is_identifier_start_char(cp: u32) -> bool {
112    char::from_u32(cp).is_some_and(|ch| unicode_id_start::is_id_start(ch) || ch == '$' || ch == '_')
113}
114
115pub fn is_identifier_part_char(cp: u32) -> bool {
116    char::from_u32(cp).is_some_and(|ch| unicode_id_start::is_id_continue(ch) || ch == '$')
117}
118
119pub fn map_control_escape(cp: u32) -> Option<u32> {
120    match char::from_u32(cp) {
121        Some('f') => Some(0x0c),
122        Some('n') => Some(0x0a),
123        Some('r') => Some(0x0d),
124        Some('t') => Some(0x09),
125        Some('v') => Some(0x0b),
126        _ => None,
127    }
128}
129
130pub fn map_c_ascii_letter(cp: u32) -> Option<u32> {
131    char::from_u32(cp)
132        .filter(char::is_ascii_alphabetic)
133        .map(|_| cp % 0x20)
134}
135
136pub fn map_hex_digit(cp: u32) -> Option<u32> {
137    char::from_u32(cp)
138        .filter(char::is_ascii_hexdigit)
139        .and_then(|c| c.to_digit(16))
140}