1use super::*;
2use libsugar::Also;
3use serde::{Deserialize, Serialize};
4use std::convert::From;
5use std::fmt;
6use std::fmt::{Display, Formatter};
7use std::string::ToString;
8
9#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash, PartialOrd, Ord, Deserialize, Serialize)]
11pub enum Char {
12 Char(char, Loc),
14 Wrap(Loc),
16}
17impl Char {
18 #[inline]
21 pub fn char<R>(&self, mut f: impl FnMut(char, Loc) -> R) -> Option<R> {
22 match self {
23 Char::Char(c, l) => Some(f(*c, *l)),
24 _ => None,
25 }
26 }
27 #[inline]
30 pub fn wrap<R>(&self, mut f: impl FnMut(Loc) -> R) -> Option<R> {
31 match self {
32 Char::Wrap(l) => Some(f(*l)),
33 _ => None,
34 }
35 }
36 #[inline]
38 pub fn is_char(&self) -> bool {
39 matches!(self, Char::Char(_, _))
40 }
41 #[inline]
43 pub fn is_wrap(&self) -> bool {
44 matches!(self, Char::Wrap(_))
45 }
46
47 #[inline]
49 pub fn char_eq(&self, other: &Self) -> bool {
50 match self {
51 Char::Char(c, _) => {
52 if let Char::Char(oc, _) = other {
53 c == oc
54 } else {
55 false
56 }
57 }
58 Char::Wrap(_) => matches!(other, Char::Wrap(_)),
59 }
60 }
61 #[inline]
63 pub fn char_ne(&self, other: &Self) -> bool {
64 !self.char_eq(other)
65 }
66 #[inline]
69 pub fn c(&self) -> char {
70 match self {
71 Char::Char(c, _) => *c,
72 Char::Wrap(_) => '\n',
73 }
74 }
75}
76impl GetLoc for Char {
77 #[inline]
78 fn loc(&self) -> Loc {
79 match self {
80 Char::Char(_, l) => *l,
81 Char::Wrap(l) => *l,
82 }
83 }
84}
85impl Display for Char {
86 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
87 match self {
88 Char::Char(c, _) => write!(f, "Char({})", c),
89 Char::Wrap(_) => write!(f, "Wrap"),
90 }
91 }
92}
93impl PartialEq<char> for Char {
94 fn eq(&self, other: &char) -> bool {
97 match self {
98 Char::Char(c, _) => *c == *other,
99 Char::Wrap(_) => '\n' == *other,
100 }
101 }
102}
103impl Into<char> for Char {
104 #[inline]
105 fn into(self) -> char {
106 self.c()
107 }
108}
109impl GetString for Char {
110 #[inline]
111 fn get_string(&self) -> String {
112 self.c().to_string()
113 }
114}
115impl GetChar for Char {
116 #[inline]
117 fn get_char(&self) -> char {
118 self.c()
119 }
120}
121
122#[derive(Debug, Clone, Hash, PartialOrd, Ord, PartialEq, Eq, Default)]
126pub struct CharChars<I: Iterator<Item = char>> {
127 iter: I,
128 loc: Loc,
129 isr: Option<Loc>,
130 end: bool,
131 nextret: Option<Char>,
132}
133impl<I: Iterator<Item = char>> CharChars<I> {
134 pub fn new(iter: I) -> Self {
135 Self {
136 iter,
137 loc: Loc::new(),
138 isr: None,
139 end: false,
140 nextret: None,
141 }
142 }
143}
144impl<I: Iterator<Item = char>> From<I> for CharChars<I> {
145 #[inline]
146 fn from(iter: I) -> Self {
147 Self::new(iter)
148 }
149}
150impl<I: Iterator<Item = char>> Iterator for CharChars<I> {
151 type Item = Char;
152
153 fn next(&mut self) -> Option<Self::Item> {
154 if let Some(r) = self.nextret {
155 self.nextret = None;
156 return Some(r);
157 }
158 if self.end {
159 return None;
160 }
161 loop {
162 let n = self.iter.next();
163 if let Some(c) = n {
164 if let Some(l) = self.isr {
165 if c == '\n' {
166 self.isr = None;
167 return Some(Char::Wrap(l)).also(|_| {
168 self.loc.offset += 1;
169 });
170 } else {
171 if c == '\r' {
172 self.isr = Some(self.loc);
173 self.loc.offset += 1;
174 self.loc.char = 0;
175 self.loc.line += 1;
176 return Some(Char::Wrap(l));
177 } else {
178 self.isr = None;
179 self.nextret = Some(Char::Char(c, self.loc));
180 self.loc.offset += 1;
181 self.loc.char += 1;
182 return Some(Char::Wrap(l));
183 }
184 }
185 } else {
186 if c == '\r' {
187 self.isr = Some(self.loc);
188 self.loc.offset += 1;
189 self.loc.char = 0;
190 self.loc.line += 1;
191 } else if c == '\n' {
192 return Some(Char::Wrap(self.loc)).also(|_| {
193 self.loc.offset += 1;
194 self.loc.char = 0;
195 self.loc.line += 1;
196 });
197 } else {
198 return Some(Char::Char(c, self.loc)).also(|_| {
199 self.loc.offset += 1;
200 self.loc.char += 1;
201 });
202 }
203 }
204 } else {
205 if let Some(l) = self.isr {
206 self.end = true;
207 return Some(Char::Wrap(l));
208 } else {
209 self.end = true;
210 return None;
211 }
212 }
213 }
214 }
215}
216
217#[cfg(test)]
218mod tests {
219 use super::{Char, CharChars, Loc};
220
221 #[test]
222 fn test_char_chars() {
223 let code = "a\nb\rc\r\nd";
224 let mut cc = CharChars::new(code.chars());
225
226 assert_eq!(cc.next(), Some(Char::Char('a', Loc::new_at(0, 0, 0))));
227 assert_eq!(cc.next(), Some(Char::Wrap(Loc::new_at(1, 0, 1))));
228 assert_eq!(cc.next(), Some(Char::Char('b', Loc::new_at(2, 1, 0))));
229 assert_eq!(cc.next(), Some(Char::Wrap(Loc::new_at(3, 1, 1))));
230 assert_eq!(cc.next(), Some(Char::Char('c', Loc::new_at(4, 2, 0))));
231 assert_eq!(cc.next(), Some(Char::Wrap(Loc::new_at(5, 2, 1))));
232 assert_eq!(cc.next(), Some(Char::Char('d', Loc::new_at(7, 3, 0))));
233 assert_eq!(cc.next(), None);
234 }
235}