keyword_parser/
transition.rs1use transition_table:: { Optional, Transition };
2use combine::{
3 ParseError, ParseResult, Parser, RangeStream,
4 stream::uncons,
5};
6use core::marker::PhantomData;
7
8struct Keyword<K, J, V, T>
9where
10 T: AsRef<[Transition<K, J, V>]>,
11{
12 tbl: T,
13 _key: PhantomData<K>,
14 _idx: PhantomData<J>,
15 _value: PhantomData<V>,
16}
17
18impl<K, J, V, T> Keyword<K, J, V, T>
19where
20 T: AsRef<[Transition<K, J, V>]>,
21{
22 fn new(tbl: T) -> Self {
23 Self {
24 tbl,
25 _key: PhantomData,
26 _idx: PhantomData,
27 _value: PhantomData,
28 }
29 }
30}
31
32impl<I, J, V, T> Parser<I> for Keyword<I::Token, J, V, T>
33where
34 I: RangeStream,
35 I::Token: Copy + Ord,
36 I::Error: ParseError<I::Token, I::Range, I::Position>,
37 J: Copy + Into<usize>,
38 V: Optional,
39 T: AsRef<[Transition<I::Token, J, V>]>,
40{
41 type Output = V::Inner;
42 type PartialState = ();
43
44 fn parse_lazy(&mut self, input: &mut I) -> ParseResult<Self::Output, I::Error> {
45 let position = input.position();
46 let mut checkpoint = input.checkpoint();
47 let tbl = self.tbl.as_ref();
48 let mut e = match tbl.last() {
49 Some(e) => e,
50 None => {
51 let mut e = I::Error::empty(position);
52
53 e.add_message("table is empty!!");
54 return ParseResult::PeekErr(e.into());
55 },
56 };
57 let mut last_match: Option<V::Inner> = None;
58
59 loop {
60 match uncons(input) {
61 ParseResult::PeekOk(c) | ParseResult::CommitOk(c) => {
62 let r = &tbl[e.1.into()..e.2.into()];
63
64 match r.binary_search_by_key(&c, |e| e.0) {
65 Ok(j) => {
66 let found = &r[j];
67
68 if let Some(v) = found.3.inner() {
69 checkpoint = input.checkpoint();
70 last_match = Some(v);
71 }
72 e = found;
73 },
74 Err(_) => break match input.reset(checkpoint) {
75 Ok(_) => match last_match {
76 Some(v) => ParseResult::CommitOk(v),
77 None => ParseResult::PeekErr(I::Error::empty(position).into()),
78 },
79 Err(e) => ParseResult::CommitErr(e),
80 },
81 }
82 },
83 ParseResult::PeekErr(err) => break match input.reset(checkpoint) {
84 Ok(_) => match last_match {
85 Some(v) => ParseResult::CommitOk(v),
86 None => ParseResult::PeekErr(err),
87 },
88 Err(e) => ParseResult::PeekErr(e.into()),
89 },
90 ParseResult::CommitErr(err) => break match input.reset(checkpoint) {
91 Ok(_) => match last_match {
92 Some(v) => ParseResult::CommitOk(v),
93 None => ParseResult::CommitErr(err),
94 },
95 Err(e) => ParseResult::CommitErr(e),
96 },
97 }
98 }
99 }
100}
101
102pub fn keyword<I, J, V, T>(tbl: T) -> impl Parser<I, Output = V::Inner>
157where
158 I: RangeStream,
159 I::Token: Copy + Ord,
160 I::Error: ParseError<I::Token, I::Range, I::Position>,
161 J: Copy + Into<usize>,
162 V: Optional,
163 T: AsRef<[Transition<I::Token, J, V>]>,
164{
165 Keyword::new(tbl)
166}