Skip to main content

chasa/parser/
token.rs

1use core::marker::PhantomData;
2
3use reborrow_generic::Reborrow;
4
5use crate::back::RbBack;
6use crate::error::ErrorSink;
7use crate::error::std::Unexpected;
8use crate::input::{In, Input};
9use crate::parser::{Parser, ParserMut, ParserOnce, SkipParser, SkipParserMut, SkipParserOnce};
10
11pub trait ExpectedItem<It> {
12    fn eq_item(&self, actual: &It) -> bool;
13}
14
15impl<It: PartialEq> ExpectedItem<It> for It {
16    #[inline]
17    fn eq_item(&self, actual: &It) -> bool {
18        self == actual
19    }
20}
21
22impl<'a, It: PartialEq> ExpectedItem<It> for &'a It {
23    #[inline]
24    fn eq_item(&self, actual: &It) -> bool {
25        *self == actual
26    }
27}
28
29pub trait ItemSeq<It>: Clone {
30    type Item: ExpectedItem<It>;
31    type Iter: Iterator<Item = Self::Item>;
32    fn iter(&self) -> Self::Iter;
33}
34
35impl<'a, It: PartialEq + Clone> ItemSeq<It> for &'a [It] {
36    type Item = &'a It;
37    type Iter = core::slice::Iter<'a, It>;
38    #[inline]
39    fn iter(&self) -> Self::Iter {
40        (*self).iter()
41    }
42}
43
44impl<'a, It: PartialEq + Clone, const N: usize> ItemSeq<It> for &'a [It; N] {
45    type Item = &'a It;
46    type Iter = core::slice::Iter<'a, It>;
47    #[inline]
48    fn iter(&self) -> Self::Iter {
49        self.as_slice().iter()
50    }
51}
52
53impl<'a> ItemSeq<char> for &'a str {
54    type Item = char;
55    type Iter = core::str::Chars<'a>;
56    #[inline]
57    fn iter(&self) -> Self::Iter {
58        self.chars()
59    }
60}
61
62/// Match an exact item sequence.
63///
64/// ```rust
65/// use chasa::prelude::*;
66///
67/// let out = "hello!".test(tag("hello"));
68/// assert_eq!(out, Some(()));
69///
70/// let expected = ['a', 'b', 'c'];
71/// let out = "abc".test(tag(&expected));
72/// assert_eq!(out, Some(()));
73///
74/// let out = "axc".test(tag(&expected));
75/// assert_eq!(out, None);
76/// ```
77#[inline(always)]
78pub fn tag<S, A>(expected: S) -> Tag<S, A> {
79    Tag(expected, PhantomData)
80}
81
82#[derive(Clone, Copy, Debug, Hash)]
83pub struct Tag<S, A>(pub(crate) S, PhantomData<fn() -> A>);
84
85#[inline]
86fn run_tag<I, N, L, E, S>(mut i: In<I, N, L, E>, expected: S) -> Option<()>
87where
88    I: Input,
89    N: Reborrow,
90    L: RbBack,
91    E: ErrorSink<I::Pos>,
92    S: ItemSeq<I::Item>,
93    Unexpected<I::Item>: Into<E::Error>,
94{
95    for expected in expected.iter() {
96        let p0 = i.input.pos();
97        match i.input.next() {
98            Some(actual) if expected.eq_item(&actual) => {}
99            Some(actual) => {
100                let p1 = i.input.pos();
101                E::push(
102                    E::shorten_mut(&mut i.errors),
103                    p0..p1,
104                    Unexpected::Item(actual).into(),
105                );
106                return None;
107            }
108            None => {
109                let p1 = i.input.pos();
110                E::push(
111                    E::shorten_mut(&mut i.errors),
112                    p0..p1,
113                    Unexpected::EndOfInput.into(),
114                );
115                return None;
116            }
117        }
118    }
119    Some(())
120}
121
122impl<I, N, L, E, S> SkipParserOnce<I, N, L, E> for Tag<S, (I, N, L, E)>
123where
124    I: Input,
125    N: Reborrow,
126    L: RbBack,
127    E: ErrorSink<I::Pos>,
128    S: ItemSeq<I::Item>,
129    Unexpected<I::Item>: Into<E::Error>,
130{
131    #[inline]
132    fn discard_once(self, i: In<I, N, L, E>) -> Option<()> {
133        run_tag(i, self.0)
134    }
135}
136
137impl<I, N, L, E, S> SkipParserMut<I, N, L, E> for Tag<S, (I, N, L, E)>
138where
139    I: Input,
140    N: Reborrow,
141    L: RbBack,
142    E: ErrorSink<I::Pos>,
143    S: ItemSeq<I::Item>,
144    Unexpected<I::Item>: Into<E::Error>,
145{
146    #[inline]
147    fn discard_mut(&mut self, i: In<I, N, L, E>) -> Option<()> {
148        run_tag(i, self.0.clone())
149    }
150}
151
152impl<I, N, L, E, S> SkipParser<I, N, L, E> for Tag<S, (I, N, L, E)>
153where
154    I: Input,
155    N: Reborrow,
156    L: RbBack,
157    E: ErrorSink<I::Pos>,
158    S: ItemSeq<I::Item>,
159    Unexpected<I::Item>: Into<E::Error>,
160{
161    #[inline]
162    fn discard(&self, i: In<I, N, L, E>) -> Option<()> {
163        run_tag(i, self.0.clone())
164    }
165}
166
167impl<I, N, L, E, S> ParserOnce<I, N, L, E> for Tag<S, (I, N, L, E)>
168where
169    I: Input,
170    N: Reborrow,
171    L: RbBack,
172    E: ErrorSink<I::Pos>,
173    S: ItemSeq<I::Item>,
174    Unexpected<I::Item>: Into<E::Error>,
175{
176    type Out = ();
177    #[inline]
178    fn parse_once(self, i: In<I, N, L, E>) -> Option<()> {
179        run_tag(i, self.0)
180    }
181}
182
183impl<I, N, L, E, S> ParserMut<I, N, L, E> for Tag<S, (I, N, L, E)>
184where
185    I: Input,
186    N: Reborrow,
187    L: RbBack,
188    E: ErrorSink<I::Pos>,
189    S: ItemSeq<I::Item>,
190    Unexpected<I::Item>: Into<E::Error>,
191{
192    #[inline]
193    fn parse_mut(&mut self, i: In<I, N, L, E>) -> Option<()> {
194        run_tag(i, self.0.clone())
195    }
196}
197
198impl<I, N, L, E, S> Parser<I, N, L, E> for Tag<S, (I, N, L, E)>
199where
200    I: Input,
201    N: Reborrow,
202    L: RbBack,
203    E: ErrorSink<I::Pos>,
204    S: ItemSeq<I::Item>,
205    Unexpected<I::Item>: Into<E::Error>,
206{
207    #[inline]
208    fn parse(&self, i: In<I, N, L, E>) -> Option<()> {
209        run_tag(i, self.0.clone())
210    }
211}