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
109#[derive(Clone)]
111pub enum Unit {
112 Symbol(Box<str>, Span),
114 Parser(Parser),
116}
117
118impl Unit {
119 pub fn span(&self) -> Span {
121 match self {
122 Self::Symbol(_, span) => *span,
123 Self::Parser(parser) => parser.span,
124 }
125 }
126
127 pub fn symbol(self) -> Result<Box<str>> {
129 if let Self::Symbol(name, _) = self {
130 Ok(name)
131 } else {
132 Err(ErrorKind::ListNotAllowed.into())
133 }
134 }
135
136 pub fn parser(self) -> Result<Parser> {
138 if let Self::Parser(parser) = self {
139 Ok(parser)
140 } else {
141 Err(ErrorKind::SymbolNotAllowed.into())
142 }
143 }
144
145 pub fn substitute(&mut self, variable: &str, value: &str) {
147 match self {
148 Self::Symbol(name, _) => {
149 if name.as_ref() == variable {
150 *name = value.into();
151 }
152 }
153 Self::Parser(parser) => parser.substitute(variable, value),
154 }
155 }
156}
157
158impl<C: Context> Parsable<C> for Unit {
159 fn parse_symbol(name: Box<str>, span: Span, _context: &C) -> Result<Self> {
160 Ok(Self::Symbol(name, span))
161 }
162
163 fn parse_list(parser: &mut Parser, _context: &C) -> Result<Self> {
164 let form = std::mem::take(&mut parser.form);
165 let span = parser.span;
166 Ok(Self::Parser(Parser {
167 form,
168 count: 0,
169 span,
170 }))
171 }
172}
173
174#[allow(clippy::boxed_local)]
176pub trait Parsable<C: Context>: Sized {
177 fn parse_symbol(_name: Box<str>, _span: Span, _context: &C) -> Result<Self> {
179 Err(ErrorKind::SymbolNotAllowed.into())
180 }
181
182 fn parse_list(_parser: &mut Parser, _context: &C) -> Result<Self> {
184 Err(ErrorKind::ListNotAllowed.into())
185 }
186}
187
188fn parse<C: Context, P: Parsable<C>>(unit: Unit, context: &C) -> Result<P> {
189 match unit {
190 Unit::Symbol(name, span) => {
191 Parsable::parse_symbol(name, span, context).map_err(|e| e.at(span))
192 }
193 Unit::Parser(mut parser) => {
194 let span = parser.span;
195 Parsable::parse_list(&mut parser, context).map_err(|e| e.at(span))
196 }
197 }
198}
199
200impl<C: Context, T: Parsable<C>> Parsable<C> for Box<T> {
201 fn parse_symbol(name: Box<str>, span: Span, context: &C) -> Result<Self> {
202 Ok(Self::new(Parsable::parse_symbol(name, span, context)?))
203 }
204
205 fn parse_list(parser: &mut Parser, context: &C) -> Result<Self> {
206 Ok(Self::new(parser.parse_list(context)?))
207 }
208}
209
210impl<C: Context, T: Parsable<C>> Parsable<C> for Vec<T> {
211 fn parse_list(parser: &mut Parser, context: &C) -> Result<Self> {
212 let Parser { form, count, .. } = parser;
213 form.drain(..)
214 .rev()
215 .map(|unit| {
216 *count += 1;
217 parse(unit, context)
218 })
219 .collect()
220 }
221}
222
223impl<C: Context> Parsable<C> for String {
224 fn parse_symbol(name: Box<str>, _span: Span, _context: &C) -> Result<Self> {
225 Ok(name.into())
226 }
227}
228
229impl<C: Context> Parsable<C> for Box<str> {
230 fn parse_symbol(name: Box<str>, _span: Span, _context: &C) -> Result<Self> {
231 Ok(name)
232 }
233}
234
235impl<C: Context> Parsable<C> for PathBuf {
236 fn parse_symbol(name: Box<str>, _span: Span, _context: &C) -> Result<Self> {
237 Ok(name.as_ref().into())
238 }
239}
240
241#[macro_export]
243macro_rules! derive_symbol_parsable {
244 ($t:ty) => {
245 impl<C: $crate::Context> $crate::Parsable<C> for $t {
246 fn parse_symbol(name: Box<str>, _span: $crate::Span, _context: &C) -> $crate::Result<Self> {
247 name.parse().map_err(|_| $crate::ErrorKind::StringParsing.into())
248 }
249 }
250 };
251 ($t:ty, $($rest:ty),+) => {
252 derive_symbol_parsable!($t);
253 derive_symbol_parsable!($($rest),+);
254 };
255}
256
257#[cfg(not(feature = "radix-parsing"))]
258mod numbers;
259derive_symbol_parsable!(bool);
260
261#[derive(Clone)]
263pub struct Parser {
264 form: Vec<Unit>,
265 count: usize,
266 span: Span,
267}
268
269impl Parser {
270 pub fn new<I: IntoIterator>(form: I) -> Self
272 where
273 I::Item: Into<Unit>,
274 {
275 let mut form: Vec<_> = form.into_iter().map(I::Item::into).collect();
276 form.reverse();
277 Self {
278 form,
279 count: 0,
280 span: Span::default(),
281 }
282 }
283
284 pub fn with_span(mut self, span: Span) -> Self {
286 self.span = span;
287 self
288 }
289
290 pub fn span(&self) -> Span {
292 self.span
293 }
294
295 pub fn is_empty(&self) -> bool {
297 self.form.is_empty()
298 }
299
300 pub fn substitute(&mut self, variable: &str, value: &str) {
302 for unit in &mut self.form {
303 unit.substitute(variable, value);
304 }
305 }
306
307 pub fn next_unit(&mut self) -> Option<Unit> {
309 self.count += 1;
310 self.form.pop()
311 }
312
313 pub fn parse_next<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
315 self.count += 1;
316 if let Some(token) = self.form.pop() {
317 parse(token, context)
318 } else {
319 Result::Err(Error {
320 kind: ErrorKind::NotEnoughElements(self.count),
321 span: Some(self.span),
322 })
323 }
324 }
325
326 pub fn parse_rest<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
329 let result = self.parse_list(context);
330 let count = self.form.len();
331 if count > 0 {
332 self.form.clear();
333 Err(Error {
334 kind: ErrorKind::TooManyElements(count),
335 span: Some(self.span),
336 })
337 } else {
338 result
339 }
340 }
341
342 pub fn parse_list<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
344 Parsable::parse_list(self, context)
345 }
346}
347
348impl Iterator for Parser {
349 type Item = Result<Self>;
350
351 fn next(&mut self) -> Option<Result<Self>> {
352 self.count += 1;
353 Some(self.form.pop()?.parser())
354 }
355}
356
357#[cfg(feature = "radix-parsing")]
358pub mod radix;