#![deny(missing_docs)]
use std::path::PathBuf;
use thiserror::Error;
pub trait Context {
#[cfg(feature = "radix-parsing")]
#[inline]
fn radix(&self) -> u32 {
10
}
}
impl Context for () {}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Span {
pub line: usize,
pub column: usize,
}
impl std::fmt::Display for Span {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.line + 1, self.column + 1)
}
}
#[derive(Debug, Error)]
pub enum ErrorKind {
#[error("Not enough elements: {0} more expected")]
NotEnoughElements(usize),
#[error("Too many elements: {0} less expected")]
TooManyElements(usize),
#[error("List not allowed")]
ListNotAllowed,
#[error("Symbol not allowed")]
SymbolNotAllowed,
#[error("String parsing error")]
StringParsing,
#[error("Invalid element")]
InvalidElement,
}
#[derive(Debug)]
pub struct Error {
pub kind: ErrorKind,
pub span: Option<Span>,
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(span) = self.span {
write!(f, "{span}: {}", self.kind)
} else {
write!(f, "{}", self.kind)
}
}
}
impl std::error::Error for Error {}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Self {
Self { kind, span: None }
}
}
impl Error {
fn at(self, span: Span) -> Self {
Self {
kind: self.kind,
span: self.span.or(Some(span)),
}
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Clone)]
pub enum Unit {
Symbol(Box<str>, Span),
Parser(Parser),
}
impl Unit {
pub fn span(&self) -> Span {
match self {
Self::Symbol(_, span) => *span,
Self::Parser(parser) => parser.span,
}
}
pub fn symbol(self) -> Result<Box<str>> {
if let Self::Symbol(name, _) = self {
Ok(name)
} else {
Err(ErrorKind::ListNotAllowed.into())
}
}
pub fn parser(self) -> Result<Parser> {
if let Self::Parser(parser) = self {
Ok(parser)
} else {
Err(ErrorKind::SymbolNotAllowed.into())
}
}
pub fn substitute(&mut self, variable: &str, value: &str) {
match self {
Self::Symbol(name, _) => {
if name.as_ref() == variable {
*name = value.into();
}
}
Self::Parser(parser) => parser.substitute(variable, value),
}
}
}
impl<C: Context> Parsable<C> for Unit {
fn parse_symbol(name: Box<str>, span: Span, _context: &C) -> Result<Self> {
Ok(Self::Symbol(name, span))
}
fn parse_list(parser: &mut Parser, _context: &C) -> Result<Self> {
let form = std::mem::take(&mut parser.form);
let span = parser.span;
Ok(Self::Parser(Parser {
form,
count: 0,
span,
}))
}
}
#[allow(clippy::boxed_local)]
pub trait Parsable<C: Context>: Sized {
fn parse_symbol(_name: Box<str>, _span: Span, _context: &C) -> Result<Self> {
Err(ErrorKind::SymbolNotAllowed.into())
}
fn parse_list(_parser: &mut Parser, _context: &C) -> Result<Self> {
Err(ErrorKind::ListNotAllowed.into())
}
}
fn parse<C: Context, P: Parsable<C>>(unit: Unit, context: &C) -> Result<P> {
match unit {
Unit::Symbol(name, span) => {
Parsable::parse_symbol(name, span, context).map_err(|e| e.at(span))
}
Unit::Parser(mut parser) => {
let span = parser.span;
Parsable::parse_list(&mut parser, context).map_err(|e| e.at(span))
}
}
}
impl<C: Context, T: Parsable<C>> Parsable<C> for Box<T> {
fn parse_symbol(name: Box<str>, span: Span, context: &C) -> Result<Self> {
Ok(Self::new(Parsable::parse_symbol(name, span, context)?))
}
fn parse_list(parser: &mut Parser, context: &C) -> Result<Self> {
Ok(Self::new(parser.parse_list(context)?))
}
}
impl<C: Context, T: Parsable<C>> Parsable<C> for Vec<T> {
fn parse_list(parser: &mut Parser, context: &C) -> Result<Self> {
let Parser { form, count, .. } = parser;
form.drain(..)
.rev()
.map(|unit| {
*count += 1;
parse(unit, context)
})
.collect()
}
}
impl<C: Context> Parsable<C> for String {
fn parse_symbol(name: Box<str>, _span: Span, _context: &C) -> Result<Self> {
Ok(name.into())
}
}
impl<C: Context> Parsable<C> for Box<str> {
fn parse_symbol(name: Box<str>, _span: Span, _context: &C) -> Result<Self> {
Ok(name)
}
}
impl<C: Context> Parsable<C> for PathBuf {
fn parse_symbol(name: Box<str>, _span: Span, _context: &C) -> Result<Self> {
Ok(name.as_ref().into())
}
}
#[macro_export]
macro_rules! derive_symbol_parsable {
($t:ty) => {
impl<C: $crate::Context> $crate::Parsable<C> for $t {
fn parse_symbol(name: Box<str>, _span: $crate::Span, _context: &C) -> $crate::Result<Self> {
name.parse().map_err(|_| $crate::ErrorKind::StringParsing.into())
}
}
};
($t:ty, $($rest:ty),+) => {
derive_symbol_parsable!($t);
derive_symbol_parsable!($($rest),+);
};
}
#[cfg(not(feature = "radix-parsing"))]
mod numbers;
derive_symbol_parsable!(bool);
#[derive(Clone)]
pub struct Parser {
form: Vec<Unit>,
count: usize,
span: Span,
}
impl Parser {
pub fn new<I: IntoIterator>(form: I) -> Self
where
I::Item: Into<Unit>,
{
let mut form: Vec<_> = form.into_iter().map(I::Item::into).collect();
form.reverse();
Self {
form,
count: 0,
span: Span::default(),
}
}
pub fn with_span(mut self, span: Span) -> Self {
self.span = span;
self
}
pub fn span(&self) -> Span {
self.span
}
pub fn is_empty(&self) -> bool {
self.form.is_empty()
}
pub fn substitute(&mut self, variable: &str, value: &str) {
for unit in &mut self.form {
unit.substitute(variable, value);
}
}
pub fn next_unit(&mut self) -> Option<Unit> {
self.count += 1;
self.form.pop()
}
pub fn parse_next<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
self.count += 1;
if let Some(token) = self.form.pop() {
parse(token, context)
} else {
Result::Err(Error {
kind: ErrorKind::NotEnoughElements(self.count),
span: Some(self.span),
})
}
}
pub fn parse_rest<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
let result = self.parse_list(context);
let count = self.form.len();
if count > 0 {
self.form.clear();
Err(Error {
kind: ErrorKind::TooManyElements(count),
span: Some(self.span),
})
} else {
result
}
}
pub fn parse_list<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
Parsable::parse_list(self, context)
}
}
impl Iterator for Parser {
type Item = Result<Self>;
fn next(&mut self) -> Option<Result<Self>> {
self.count += 1;
Some(self.form.pop()?.parser())
}
}
#[cfg(feature = "radix-parsing")]
pub mod radix;