parse_js/
char.rs

1use core::ops::RangeInclusive;
2use once_cell::sync::Lazy;
3
4#[derive(Clone)]
5pub struct CharFilter {
6  table: [bool; 256],
7}
8
9impl CharFilter {
10  pub fn new() -> CharFilter {
11    CharFilter {
12      table: [false; 256],
13    }
14  }
15
16  pub fn add_char(&mut self, c: u8) {
17    self.table[c as usize] = true;
18  }
19
20  pub fn add_chars(&mut self, chars: RangeInclusive<u8>) {
21    for c in chars {
22      self.table[c as usize] = true;
23    }
24  }
25
26  pub fn add_chars_from_slice(&mut self, chars: &[u8]) {
27    for c in chars {
28      self.table[*c as usize] = true;
29    }
30  }
31
32  pub fn clone(&self) -> CharFilter {
33    CharFilter { table: self.table }
34  }
35
36  pub fn invert(&mut self) {
37    for i in 0..256 {
38      self.table[i] = !self.table[i];
39    }
40  }
41
42  pub fn has(&self, c: u8) -> bool {
43    unsafe { *self.table.get_unchecked(c as usize) }
44  }
45
46  pub fn iter(&self) -> impl Iterator<Item = u8> + '_ {
47    self
48      .table
49      .iter()
50      .enumerate()
51      .filter(|(_, e)| **e)
52      .map(|(c, _)| c as u8)
53  }
54}
55
56// WARNING: These do not consider Unicode characters allowed by spec.
57pub const ID_START_CHARSTR: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
58pub const ID_CONTINUE_CHARSTR: &[u8] =
59  b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
60
61pub static DIGIT: Lazy<CharFilter> = Lazy::new(|| {
62  let mut filter = CharFilter::new();
63  filter.add_chars(b'0'..=b'9');
64  filter
65});
66
67pub static DIGIT_BIN: Lazy<CharFilter> = Lazy::new(|| {
68  let mut filter = CharFilter::new();
69  filter.add_chars(b'0'..=b'1');
70  filter
71});
72
73pub static DIGIT_HEX: Lazy<CharFilter> = Lazy::new(|| {
74  let mut filter = CharFilter::new();
75  filter.add_chars(b'0'..=b'9');
76  filter.add_chars(b'a'..=b'f');
77  filter.add_chars(b'A'..=b'F');
78  filter
79});
80
81pub static DIGIT_OCT: Lazy<CharFilter> = Lazy::new(|| {
82  let mut filter = CharFilter::new();
83  filter.add_chars(b'0'..=b'8');
84  filter
85});
86
87pub static ID_START: Lazy<CharFilter> = Lazy::new(|| {
88  let mut filter = CharFilter::new();
89  filter.add_chars_from_slice(ID_START_CHARSTR);
90  filter
91});
92
93pub static ID_CONTINUE: Lazy<CharFilter> = Lazy::new(|| {
94  let mut filter = ID_START.clone();
95  // WARNING: Does not consider Unicode characters allowed by spec.
96  filter.add_chars(b'0'..=b'9');
97  filter
98});
99
100pub static ID_CONTINUE_JSX: Lazy<CharFilter> = Lazy::new(|| {
101  let mut filter = ID_CONTINUE.clone();
102  filter.add_char(b'-');
103  filter
104});
105
106pub static ID_CONTINUE_OR_PARENTHESIS_CLOSE_OR_BRACKET_CLOSE: Lazy<CharFilter> = Lazy::new(|| {
107  let mut filter = ID_CONTINUE.clone();
108  filter.add_char(b')');
109  filter.add_char(b']');
110  filter
111});
112
113pub static WHITESPACE: Lazy<CharFilter> = Lazy::new(|| {
114  let mut filter = CharFilter::new();
115  // WARNING: Does not consider Unicode whitespace allowed by spec.
116  // Horizontal tab.
117  filter.add_char(b'\x09');
118  // Line feed.
119  filter.add_char(b'\x0a');
120  // Vertical tab.
121  filter.add_char(b'\x0b');
122  // Form feed.
123  filter.add_char(b'\x0c');
124  // Carriage return.
125  filter.add_char(b'\x0d');
126  // Space.
127  filter.add_char(b'\x20');
128  filter
129});