parser_fuck/common/
chars.rs

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/// Characters and newlines with location
10#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash, PartialOrd, Ord, Deserialize, Serialize)]
11pub enum Char {
12    /// char and Loc
13    Char(char, Loc),
14    /// wrap `'\n'` | `'\r'` | `"\r\n"` and Loc
15    Wrap(Loc),
16}
17impl Char {
18    /// map char  
19    /// None if it‘s not `Char`
20    #[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    /// map wrap  
28    /// None if it’s not `Wrap`
29    #[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    /// is `Char`
37    #[inline]
38    pub fn is_char(&self) -> bool {
39        matches!(self, Char::Char(_, _))
40    }
41    /// is `Wrap`
42    #[inline]
43    pub fn is_wrap(&self) -> bool {
44        matches!(self, Char::Wrap(_))
45    }
46
47    /// just equivalent to eq, but ignore Loc
48    #[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    /// just equivalent to ne, but ignore Loc
62    #[inline]
63    pub fn char_ne(&self, other: &Self) -> bool {
64        !self.char_eq(other)
65    }
66    /// Get the char  
67    /// when it is Wrap return `'\n'`
68    #[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    /// Checks if a char is equal to it  
95    /// when it is Wrap check eq to `'\n'`
96    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//\/////////////////////////////////////////////////////////////////////////////////////////////////
123
124/// An iterator that produces [`Char`](enum.Char.html)
125#[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}