1#![deny(missing_docs)]
2
3use std::path::PathBuf;
9
10use thiserror::Error;
11
12pub trait Context {
17 #[cfg(feature = "radix-parsing")]
18 #[inline]
19 fn radix(&self) -> u32 {
21 10
22 }
23}
24
25impl Context for () {}
26
27#[derive(Debug, Error)]
29pub enum Error {
30 #[error("Not enough elements: {0} more expected")]
32 NotEnoughElements(usize),
33
34 #[error("Too many elements: {0} less expected")]
36 TooManyElements(usize),
37
38 #[error("List not allowed")]
40 ListNotAllowed,
41
42 #[error("Symbol not allowed")]
44 SymbolNotAllowed,
45
46 #[error("String parsing error")]
48 StringParsing,
49
50 #[error("Invalid element")]
52 InvalidElement,
53}
54
55pub type Result<T> = std::result::Result<T, Error>;
57
58pub enum Unit {
60 Symbol(Box<str>),
62 Parser(Parser),
64}
65
66impl Unit {
67 pub fn symbol(self) -> Result<Box<str>> {
69 if let Self::Symbol(name) = self {
70 Ok(name)
71 } else {
72 Err(Error::ListNotAllowed)
73 }
74 }
75
76 pub fn parser(self) -> Result<Parser> {
78 if let Self::Parser(parser) = self {
79 Ok(parser)
80 } else {
81 Err(Error::SymbolNotAllowed)
82 }
83 }
84}
85
86impl<C: Context> Parsable<C> for Unit {
87 fn parse_symbol(name: Box<str>, _context: &C) -> Result<Self> {
88 Ok(Self::Symbol(name))
89 }
90
91 fn parse_list(parser: &mut Parser, _context: &C) -> Result<Self> {
92 let form = std::mem::take(&mut parser.form);
93 Ok(Self::Parser(Parser { form, count: 0 }))
94 }
95}
96
97pub trait Parsable<C: Context>: Sized {
99 fn parse_symbol(_name: Box<str>, _context: &C) -> Result<Self> {
101 Err(Error::SymbolNotAllowed)
102 }
103
104 fn parse_list(_parser: &mut Parser, _context: &C) -> Result<Self> {
106 Err(Error::ListNotAllowed)
107 }
108}
109
110fn parse<C: Context, P: Parsable<C>>(unit: Unit, context: &C) -> Result<P> {
111 use Unit::*;
112 match unit {
113 Symbol(name) => Parsable::parse_symbol(name, context),
114 Parser(mut parser) => parser.parse_rest(context),
115 }
116}
117
118impl<C: Context, T: Parsable<C>> Parsable<C> for Box<T> {
119 fn parse_symbol(name: Box<str>, context: &C) -> Result<Self> {
120 Ok(Self::new(Parsable::parse_symbol(name, context)?))
121 }
122
123 fn parse_list(parser: &mut Parser, context: &C) -> Result<Self> {
124 Ok(Self::new(parser.parse_list(context)?))
125 }
126}
127
128impl<C: Context, T: Parsable<C>> Parsable<C> for Vec<T> {
129 fn parse_list(parser: &mut Parser, context: &C) -> Result<Self> {
130 let Parser { form, count } = parser;
131 form.drain(..)
132 .rev()
133 .map(|unit| {
134 *count += 1;
135 parse(unit, context)
136 })
137 .collect()
138 }
139}
140
141impl<C: Context> Parsable<C> for String {
142 fn parse_symbol(name: Box<str>, _context: &C) -> Result<Self> {
143 Ok(name.into())
144 }
145}
146
147impl<C: Context> Parsable<C> for Box<str> {
148 fn parse_symbol(name: Box<str>, _context: &C) -> Result<Self> {
149 Ok(name)
150 }
151}
152
153impl<C: Context> Parsable<C> for PathBuf {
154 fn parse_symbol(name: Box<str>, _context: &C) -> Result<Self> {
155 Ok(name.as_ref().into())
156 }
157}
158
159#[macro_export]
161macro_rules! derive_symbol_parsable {
162 ($t:ty) => {
163 impl<C: $crate::Context> $crate::Parsable<C> for $t {
164 fn parse_symbol(name: Box<str>, _context: &C) -> $crate::Result<Self> {
165 name.parse().map_err(|_| $crate::Error::StringParsing)
166 }
167 }
168 };
169 ($t:ty, $($rest:ty),+) => {
170 derive_symbol_parsable!($t);
171 derive_symbol_parsable!($($rest),+);
172 };
173}
174
175#[cfg(not(feature = "radix-parsing"))]
176mod numbers;
177derive_symbol_parsable!(bool);
178
179pub struct Parser {
181 form: Vec<Unit>,
182 count: usize,
183}
184
185impl Parser {
186 pub fn new<I: IntoIterator>(form: I) -> Self
188 where
189 I::Item: Into<Unit>,
190 {
191 let mut form: Vec<_> = form.into_iter().map(I::Item::into).collect();
192 form.reverse();
193 Self { form, count: 0 }
194 }
195
196 pub fn is_empty(&self) -> bool {
198 self.form.is_empty()
199 }
200
201 pub fn next_unit(&mut self) -> Option<Unit> {
203 self.count += 1;
204 self.form.pop()
205 }
206
207 pub fn parse_next<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
209 self.count += 1;
210 if let Some(token) = self.form.pop() {
211 parse(token, context)
212 } else {
213 Result::Err(Error::NotEnoughElements(self.count))
214 }
215 }
216
217 pub fn parse_rest<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
220 let result = self.parse_list(context);
221 let count = self.form.len();
222 if count > 0 {
223 self.form.clear();
224 Err(Error::TooManyElements(count))
225 } else {
226 result
227 }
228 }
229
230 pub fn parse_list<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
232 Parsable::parse_list(self, context)
233 }
234}
235
236impl Iterator for Parser {
237 type Item = Result<Self>;
238
239 fn next(&mut self) -> Option<Result<Self>> {
240 self.count += 1;
241 Some(self.form.pop()?.parser())
242 }
243}
244
245#[cfg(feature = "radix-parsing")]
246pub mod radix;