1use super::{bits::HasBits, HasSpan};
2use crate::{Result, TokenizerError, UnnamedTokenizerError};
3use miette::{NamedSource, SourceOffset, SourceSpan};
4
5#[derive(Debug, Clone)]
6pub struct Cursor<T: HasBits + Clone, M = ()> {
7 src: T,
8 inner: Vec<T::Bit>,
9 pos: usize,
10 meta: M,
11}
12
13impl<T: HasBits + Clone, M: Default> Cursor<T, M> {
14 pub fn new(data: T) -> Self {
15 Self {
16 src: data.clone(),
17 inner: data.get_bits(),
18 pos: 0,
19 meta: M::default(),
20 }
21 }
22}
23
24impl<T: HasBits + Clone> Cursor<T, NamedSource<String>> {
25 pub fn new_from_src(file: impl AsRef<str>, code: impl AsRef<str>, data: T) -> Self {
26 Self {
27 src: data.clone(),
28 inner: data.get_bits(),
29 pos: 0,
30 meta: NamedSource::new(file, code.as_ref().into()),
31 }
32 }
33}
34
35impl<T: HasBits + Clone> Cursor<T, String> {
36 pub fn new_from_src(code: impl AsRef<str>, data: T) -> Self {
37 Self {
38 src: data.clone(),
39 inner: data.get_bits(),
40 pos: 0,
41 meta: code.as_ref().into(),
42 }
43 }
44}
45
46impl<T: HasBits + Clone, M> Cursor<T, M> {
47 pub fn is_empty(&self) -> bool {
48 self.inner.len() <= self.pos
49 }
50
51 pub fn has_next(&self) -> bool {
52 !self.is_empty()
53 }
54
55 pub fn next(&mut self) -> Option<T::Bit> {
56 self.pos += 1;
57 self.inner.get(self.pos - 1).cloned()
58 }
59
60 pub fn peek(&self) -> Option<T::Bit> {
61 self.inner.get(self.pos).cloned()
62 }
63
64 pub fn peek_ahead(&self, num: usize) -> Option<T::Bit> {
65 self.inner.get(self.pos + num).cloned()
66 }
67
68 pub fn skip(&mut self, num: usize) {
69 self.pos += num;
70 }
71
72 pub fn pos(&self) -> usize {
73 self.pos
74 }
75}
76
77impl<T: HasBits + Clone + FromIterator<T::Bit>, M> Cursor<T, M> {
78 pub fn peek_many(&self, start: usize, num: usize) -> Option<T> {
79 let mut parts = Vec::new();
80
81 for i in 0..num {
82 if let Some(bit) = self.peek_ahead(start + i) {
83 parts.push(bit);
84 } else {
85 return None;
86 }
87 }
88
89 Some(parts.iter().cloned().collect())
90 }
91}
92
93impl<T: HasBits + Clone> Cursor<T, String> {
94 pub fn source(&self) -> String {
95 self.meta.clone()
96 }
97}
98
99impl<B: Clone + HasSpan, T: HasBits<Bit = B> + Clone> Cursor<T, String> {
100 pub fn next_or_die(&mut self) -> Result<T::Bit> {
101 self.pos += 1;
102
103 match self.inner.get(self.pos - 1).cloned() {
104 Some(v) => Ok(v),
105 None => Err(UnnamedTokenizerError {
106 src: self.source(),
107 at: self.inner.get(self.pos - 2).clone().unwrap().get_span(),
108 err: "Unexpected end of file!".into(),
109 }
110 .into()),
111 }
112 }
113}
114
115impl<T: HasBits + Clone> Cursor<T, NamedSource<String>> {
116 pub fn source(&self) -> NamedSource<String> {
117 self.meta.clone()
118 }
119
120 pub fn next_or_die(&mut self, span: SourceSpan) -> Result<T::Bit> {
121 self.pos += 1;
122
123 match self.inner.get(self.pos - 1).cloned() {
124 Some(v) => Ok(v),
125 None => Err(TokenizerError {
126 src: self.source(),
127 at: span,
128 err: "Unexpected end of file!".into(),
129 }
130 .into()),
131 }
132 }
133}
134
135impl Cursor<String, String> {
136 pub fn new_from_code(data: impl AsRef<str>) -> Self {
137 let s = data.as_ref().to_string();
138
139 Self {
140 src: s.clone(),
141 inner: s.chars().collect(),
142 pos: 0,
143 meta: s,
144 }
145 }
146
147 fn find_line(&self) -> usize {
148 let mut lines = 0;
149
150 for item in &self.inner[0..self.pos] {
151 if *item == '\n' {
152 lines += 1;
153 }
154 }
155
156 lines
157 }
158
159 fn find_char(&self) -> usize {
160 let line = self.find_line();
161 let mut lines = 0;
162 let mut chars = 0;
163
164 for item in &self.inner[0..self.pos] {
165 if *item == '\n' {
166 lines += 1;
167 } else {
168 if line == lines {
169 chars += 1;
170 }
171 }
172 }
173
174 chars
175 }
176
177 pub fn span(&self, length: usize) -> SourceSpan {
178 SourceSpan::new(
179 SourceOffset::from_location(&self.src, self.find_line() + 1, self.find_char()),
180 length,
181 )
182 }
183}
184
185impl Cursor<String, NamedSource<String>> {
186 pub fn new_from_code(file: impl AsRef<str>, data: impl AsRef<str>) -> Self {
187 let s = data.as_ref().to_string();
188
189 Self {
190 src: s.clone(),
191 inner: s.chars().collect(),
192 pos: 0,
193 meta: NamedSource::new(file, s),
194 }
195 }
196
197 fn find_line(&self) -> usize {
198 let mut lines = 0;
199
200 for item in &self.inner[0..self.pos] {
201 if *item == '\n' {
202 lines += 1;
203 }
204 }
205
206 lines
207 }
208
209 fn find_char(&self) -> usize {
210 let line = self.find_line();
211 let mut lines = 0;
212 let mut chars = 0;
213
214 for item in &self.inner[0..self.pos] {
215 if *item == '\n' {
216 lines += 1;
217 } else {
218 if line == lines {
219 chars += 1;
220 }
221 }
222 }
223
224 chars
225 }
226
227 pub fn span(&self, length: usize) -> SourceSpan {
228 SourceSpan::new(
229 SourceOffset::from_location(&self.src, self.find_line() + 1, self.find_char()),
230 length,
231 )
232 }
233}