aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/lexer/ptr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/lexer/ptr.rs')
-rw-r--r--crates/ra_syntax/src/lexer/ptr.rs166
1 files changed, 166 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/lexer/ptr.rs b/crates/ra_syntax/src/lexer/ptr.rs
new file mode 100644
index 000000000..c9a5354ea
--- /dev/null
+++ b/crates/ra_syntax/src/lexer/ptr.rs
@@ -0,0 +1,166 @@
1use TextUnit;
2
3use std::str::Chars;
4
5/// A simple view into the characters of a string.
6pub(crate) struct Ptr<'s> {
7 text: &'s str,
8 len: TextUnit,
9}
10
11impl<'s> Ptr<'s> {
12 /// Creates a new `Ptr` from a string.
13 pub fn new(text: &'s str) -> Ptr<'s> {
14 Ptr {
15 text,
16 len: 0.into(),
17 }
18 }
19
20 /// Gets the length of the remaining string.
21 pub fn into_len(self) -> TextUnit {
22 self.len
23 }
24
25 /// Gets the current character, if one exists.
26 pub fn current(&self) -> Option<char> {
27 self.chars().next()
28 }
29
30 /// Gets the nth character from the current.
31 /// For example, 0 will return the current token, 1 will return the next, etc.
32 pub fn nth(&self, n: u32) -> Option<char> {
33 let mut chars = self.chars().peekable();
34 chars.by_ref().skip(n as usize).next()
35 }
36
37 /// Checks whether the current character is `c`.
38 pub fn at(&self, c: char) -> bool {
39 self.current() == Some(c)
40 }
41
42 /// Checks whether the next characters match `s`.
43 pub fn at_str(&self, s: &str) -> bool {
44 let chars = self.chars();
45 chars.as_str().starts_with(s)
46 }
47
48 /// Checks whether the current character satisfies the predicate `p`.
49 pub fn at_p<P: Fn(char) -> bool>(&self, p: P) -> bool {
50 self.current().map(p) == Some(true)
51 }
52
53 /// Checks whether the nth character satisfies the predicate `p`.
54 pub fn nth_is_p<P: Fn(char) -> bool>(&self, n: u32, p: P) -> bool {
55 self.nth(n).map(p) == Some(true)
56 }
57
58 /// Moves to the next character.
59 pub fn bump(&mut self) -> Option<char> {
60 let ch = self.chars().next()?;
61 self.len += TextUnit::of_char(ch);
62 Some(ch)
63 }
64
65 /// Moves to the next character as long as `pred` is satisfied.
66 pub fn bump_while<F: Fn(char) -> bool>(&mut self, pred: F) {
67 loop {
68 match self.current() {
69 Some(c) if pred(c) => {
70 self.bump();
71 }
72 _ => return,
73 }
74 }
75 }
76
77 /// Returns the text up to the current point.
78 pub fn current_token_text(&self) -> &str {
79 let len: u32 = self.len.into();
80 &self.text[..len as usize]
81 }
82
83 /// Returns an iterator over the remaining characters.
84 fn chars(&self) -> Chars {
85 let len: u32 = self.len.into();
86 self.text[len as usize..].chars()
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn test_current() {
96 let ptr = Ptr::new("test");
97 assert_eq!(ptr.current(), Some('t'));
98 }
99
100 #[test]
101 fn test_nth() {
102 let ptr = Ptr::new("test");
103 assert_eq!(ptr.nth(0), Some('t'));
104 assert_eq!(ptr.nth(1), Some('e'));
105 assert_eq!(ptr.nth(2), Some('s'));
106 assert_eq!(ptr.nth(3), Some('t'));
107 assert_eq!(ptr.nth(4), None);
108 }
109
110 #[test]
111 fn test_at() {
112 let ptr = Ptr::new("test");
113 assert!(ptr.at('t'));
114 assert!(!ptr.at('a'));
115 }
116
117 #[test]
118 fn test_at_str() {
119 let ptr = Ptr::new("test");
120 assert!(ptr.at_str("t"));
121 assert!(ptr.at_str("te"));
122 assert!(ptr.at_str("test"));
123 assert!(!ptr.at_str("tests"));
124 assert!(!ptr.at_str("rust"));
125 }
126
127 #[test]
128 fn test_at_p() {
129 let ptr = Ptr::new("test");
130 assert!(ptr.at_p(|c| c == 't'));
131 assert!(!ptr.at_p(|c| c == 'e'));
132 }
133
134 #[test]
135 fn test_nth_is_p() {
136 let ptr = Ptr::new("test");
137 assert!(ptr.nth_is_p(0,|c| c == 't'));
138 assert!(!ptr.nth_is_p(1,|c| c == 't'));
139 assert!(ptr.nth_is_p(3,|c| c == 't'));
140 assert!(!ptr.nth_is_p(150,|c| c == 't'));
141 }
142
143 #[test]
144 fn test_bump() {
145 let mut ptr = Ptr::new("test");
146 assert_eq!(ptr.current(), Some('t'));
147 ptr.bump();
148 assert_eq!(ptr.current(), Some('e'));
149 ptr.bump();
150 assert_eq!(ptr.current(), Some('s'));
151 ptr.bump();
152 assert_eq!(ptr.current(), Some('t'));
153 ptr.bump();
154 assert_eq!(ptr.current(), None);
155 ptr.bump();
156 assert_eq!(ptr.current(), None);
157 }
158
159 #[test]
160 fn test_bump_while() {
161 let mut ptr = Ptr::new("test");
162 assert_eq!(ptr.current(), Some('t'));
163 ptr.bump_while(|c| c != 's');
164 assert_eq!(ptr.current(), Some('s'));
165 }
166}