1use crate::base::{Destination, Pattern, PeekableExt, Satisfies};
2use std::cell::RefCell;
3
4pub struct Token<Ref, Dest> {
5 pub predicate: fn(&Ref) -> bool,
6 pub parser: fn(Vec<Ref>) -> Dest,
7 pub at_least: usize,
8 pub skip_leading: Option<fn(&Ref) -> bool>,
9}
10
11impl<'a, Reference, RefT, D> Pattern<'a, Reference> for Token<RefT, D>
12where
13 Reference: Iterator<Item = RefT> + Clone + PeekableExt,
14{
15 type Iter = core::iter::Empty<Reference::Item>;
16 type Dest = D;
17
18 fn get_iter(&'a self) -> Self::Iter {
19 core::iter::empty()
20 }
21
22 fn consume_with_dest(
23 &'a self,
24 reference: &mut Reference,
25 dest: Option<&RefCell<Self::Dest>>,
26 ) -> bool
27 where
28 Reference::Item: Satisfies<<Self::Iter as Iterator>::Item>,
29 {
30 let mut trial = reference.clone();
31 if let Some(skip) = self.skip_leading {
32 while let Some(p) = trial.peek() {
33 if skip(p) {
34 let _ = trial.next();
35 continue;
36 }
37 break;
38 }
39 }
40 let mut collected: Vec<RefT> = Vec::new();
41
42 while let Some(peeked) = trial.peek() {
43 if (self.predicate)(peeked) {
44 if let Some(next_item) = trial.next() {
45 collected.push(next_item);
46 } else {
47 break;
48 }
49 } else {
50 break;
51 }
52 }
53
54 if collected.len() < self.at_least {
55 return false;
56 }
57 let mut advance = collected.len();
58 if let Some(skip) = self.skip_leading {
59 let mut temp = reference.clone();
60 let mut skipped = 0usize;
61 while let Some(p) = temp.peek() {
62 if skip(p) {
63 let _ = temp.next();
64 skipped += 1;
65 continue;
66 }
67 break;
68 }
69 advance += skipped;
70 }
71 for _ in 0..advance {
72 reference.next();
73 }
74
75 let parsed = (self.parser)(collected);
77
78 if let Some(dref) = dest {
79 *dref.borrow_mut() = parsed;
80 }
81
82 true
83 }
84}
85
86impl Destination<char> for usize {}
87
88fn pred_num<const N: u32>(ch: &char) -> bool {
90 ch.to_digit(N).is_some()
91}
92
93fn parse_num<const N: u32>(v: Vec<char>) -> usize {
94 v.into_iter().fold(0usize, |acc, c| {
95 acc.saturating_mul(N as usize)
96 .saturating_add(c.to_digit(N).unwrap() as usize)
97 })
98}
99
100const fn make_num<const N: u32>() -> Token<char, usize> {
101 Token {
102 predicate: pred_num::<N>,
103 parser: parse_num::<N>,
104 at_least: 1,
105 skip_leading: None,
106 }
107}
108
109pub const NUM: Token<char, usize> = make_num::<10>();
110pub const HEX: Token<char, usize> = make_num::<16>();
111pub const OCT: Token<char, usize> = make_num::<8>();
112pub const BIN: Token<char, usize> = make_num::<2>();
113
114pub const WS: Token<char, ()> = Token {
115 predicate: |ch| ch.is_whitespace(),
116 parser: |_| (),
117 at_least: 1,
118 skip_leading: None,
119};
120
121pub const ALPHABETIC: Token<char, String> = Token {
122 predicate: |ch| ch.is_alphabetic(),
123 parser: |v| v.into_iter().collect(),
124 at_least: 1,
125 skip_leading: None,
126};
127
128pub const ALPHANUMERIC: Token<char, String> = Token {
129 predicate: |ch| ch.is_alphanumeric(),
130 parser: |v| v.into_iter().collect(),
131 at_least: 1,
132 skip_leading: None,
133};