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, Clone, Copy, Default, PartialEq, Eq)]
29pub struct Span {
30 pub line: usize,
32 pub column: usize,
34}
35
36impl std::fmt::Display for Span {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 write!(f, "{}:{}", self.line + 1, self.column + 1)
39 }
40}
41
42#[derive(Debug, Error)]
44pub enum ErrorKind {
45 #[error("Not enough elements: {0} more expected")]
47 NotEnoughElements(usize),
48
49 #[error("Too many elements: {0} less expected")]
51 TooManyElements(usize),
52
53 #[error("List not allowed")]
55 ListNotAllowed,
56
57 #[error("Symbol not allowed")]
59 SymbolNotAllowed,
60
61 #[error("String parsing error")]
63 StringParsing,
64
65 #[error("Invalid element")]
67 InvalidElement,
68}
69
70#[derive(Debug)]
72pub struct Error {
73 pub kind: ErrorKind,
75 pub span: Option<Span>,
77}
78
79impl std::fmt::Display for Error {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 if let Some(span) = self.span {
82 write!(f, "{span}: {}", self.kind)
83 } else {
84 write!(f, "{}", self.kind)
85 }
86 }
87}
88
89impl std::error::Error for Error {}
90
91impl From<ErrorKind> for Error {
92 fn from(kind: ErrorKind) -> Self {
93 Error { kind, span: None }
94 }
95}
96
97impl Error {
98 fn at(self, span: Span) -> Self {
99 Error {
100 kind: self.kind,
101 span: self.span.or(Some(span)),
102 }
103 }
104}
105
106pub type Result<T> = std::result::Result<T, Error>;
108
109pub enum Unit {
111 Symbol(Box<str>, Span),
113 Parser(Parser),
115}
116
117impl Unit {
118 pub fn span(&self) -> Span {
120 match self {
121 Self::Symbol(_, span) => *span,
122 Self::Parser(parser) => parser.span,
123 }
124 }
125
126 pub fn symbol(self) -> Result<Box<str>> {
128 if let Self::Symbol(name, _) = self {
129 Ok(name)
130 } else {
131 Err(ErrorKind::ListNotAllowed.into())
132 }
133 }
134
135 pub fn parser(self) -> Result<Parser> {
137 if let Self::Parser(parser) = self {
138 Ok(parser)
139 } else {
140 Err(ErrorKind::SymbolNotAllowed.into())
141 }
142 }
143}
144
145impl<C: Context> Parsable<C> for Unit {
146 fn parse_symbol(name: Box<str>, span: Span, _context: &C) -> Result<Self> {
147 Ok(Self::Symbol(name, span))
148 }
149
150 fn parse_list(parser: &mut Parser, _context: &C) -> Result<Self> {
151 let form = std::mem::take(&mut parser.form);
152 let span = parser.span;
153 Ok(Self::Parser(Parser {
154 form,
155 count: 0,
156 span,
157 }))
158 }
159}
160
161#[allow(clippy::boxed_local)]
163pub trait Parsable<C: Context>: Sized {
164 fn parse_symbol(_name: Box<str>, _span: Span, _context: &C) -> Result<Self> {
166 Err(ErrorKind::SymbolNotAllowed.into())
167 }
168
169 fn parse_list(_parser: &mut Parser, _context: &C) -> Result<Self> {
171 Err(ErrorKind::ListNotAllowed.into())
172 }
173}
174
175fn parse<C: Context, P: Parsable<C>>(unit: Unit, context: &C) -> Result<P> {
176 match unit {
177 Unit::Symbol(name, span) => {
178 Parsable::parse_symbol(name, span, context).map_err(|e| e.at(span))
179 }
180 Unit::Parser(mut parser) => {
181 let span = parser.span;
182 Parsable::parse_list(&mut parser, context).map_err(|e| e.at(span))
183 }
184 }
185}
186
187impl<C: Context, T: Parsable<C>> Parsable<C> for Box<T> {
188 fn parse_symbol(name: Box<str>, span: Span, context: &C) -> Result<Self> {
189 Ok(Self::new(Parsable::parse_symbol(name, span, context)?))
190 }
191
192 fn parse_list(parser: &mut Parser, context: &C) -> Result<Self> {
193 Ok(Self::new(parser.parse_list(context)?))
194 }
195}
196
197impl<C: Context, T: Parsable<C>> Parsable<C> for Vec<T> {
198 fn parse_list(parser: &mut Parser, context: &C) -> Result<Self> {
199 let Parser { form, count, .. } = parser;
200 form.drain(..)
201 .rev()
202 .map(|unit| {
203 *count += 1;
204 parse(unit, context)
205 })
206 .collect()
207 }
208}
209
210impl<C: Context> Parsable<C> for String {
211 fn parse_symbol(name: Box<str>, _span: Span, _context: &C) -> Result<Self> {
212 Ok(name.into())
213 }
214}
215
216impl<C: Context> Parsable<C> for Box<str> {
217 fn parse_symbol(name: Box<str>, _span: Span, _context: &C) -> Result<Self> {
218 Ok(name)
219 }
220}
221
222impl<C: Context> Parsable<C> for PathBuf {
223 fn parse_symbol(name: Box<str>, _span: Span, _context: &C) -> Result<Self> {
224 Ok(name.as_ref().into())
225 }
226}
227
228#[macro_export]
230macro_rules! derive_symbol_parsable {
231 ($t:ty) => {
232 impl<C: $crate::Context> $crate::Parsable<C> for $t {
233 fn parse_symbol(name: Box<str>, _span: $crate::Span, _context: &C) -> $crate::Result<Self> {
234 name.parse().map_err(|_| $crate::ErrorKind::StringParsing.into())
235 }
236 }
237 };
238 ($t:ty, $($rest:ty),+) => {
239 derive_symbol_parsable!($t);
240 derive_symbol_parsable!($($rest),+);
241 };
242}
243
244#[cfg(not(feature = "radix-parsing"))]
245mod numbers;
246derive_symbol_parsable!(bool);
247
248pub struct Parser {
250 form: Vec<Unit>,
251 count: usize,
252 span: Span,
253}
254
255impl Parser {
256 pub fn new<I: IntoIterator>(form: I) -> Self
258 where
259 I::Item: Into<Unit>,
260 {
261 let mut form: Vec<_> = form.into_iter().map(I::Item::into).collect();
262 form.reverse();
263 Self {
264 form,
265 count: 0,
266 span: Span::default(),
267 }
268 }
269
270 pub fn with_span(mut self, span: Span) -> Self {
272 self.span = span;
273 self
274 }
275
276 pub fn span(&self) -> Span {
278 self.span
279 }
280
281 pub fn is_empty(&self) -> bool {
283 self.form.is_empty()
284 }
285
286 pub fn next_unit(&mut self) -> Option<Unit> {
288 self.count += 1;
289 self.form.pop()
290 }
291
292 pub fn parse_next<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
294 self.count += 1;
295 if let Some(token) = self.form.pop() {
296 parse(token, context)
297 } else {
298 Result::Err(Error {
299 kind: ErrorKind::NotEnoughElements(self.count),
300 span: Some(self.span),
301 })
302 }
303 }
304
305 pub fn parse_rest<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
308 let result = self.parse_list(context);
309 let count = self.form.len();
310 if count > 0 {
311 self.form.clear();
312 Err(Error {
313 kind: ErrorKind::TooManyElements(count),
314 span: Some(self.span),
315 })
316 } else {
317 result
318 }
319 }
320
321 pub fn parse_list<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
323 Parsable::parse_list(self, context)
324 }
325}
326
327impl Iterator for Parser {
328 type Item = Result<Self>;
329
330 fn next(&mut self) -> Option<Result<Self>> {
331 self.count += 1;
332 Some(self.form.pop()?.parser())
333 }
334}
335
336#[cfg(feature = "radix-parsing")]
337pub mod radix;