Add TaggedDispatchParser
Allows for more easily handling parsing of extensions like @{tag some arguments}@.main
parent
cb91b7b9d6
commit
18dc2f62b1
@ -0,0 +1,98 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::parse::{spanned, ParseExtensions, Spanned};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TagDispatchParseErrorBase {
|
||||
MissingTag,
|
||||
MissingParserFor(String),
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub enum TagDispatchParseError<E> {
|
||||
Base(Spanned<TagDispatchParseErrorBase>),
|
||||
User(E),
|
||||
}
|
||||
impl<E> From<Spanned<TagDispatchParseErrorBase>> for TagDispatchParseError<E> {
|
||||
fn from(o: Spanned<TagDispatchParseErrorBase>) -> Self {
|
||||
TagDispatchParseError::Base(o)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TagDispatchParser<'a, R, E> {
|
||||
map: HashMap<
|
||||
&'static str,
|
||||
Box<dyn ParseExtensions<'a, Output = R, Error = E>>,
|
||||
>,
|
||||
}
|
||||
|
||||
impl<'a, R, E> TagDispatchParser<'a, R, E> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
map: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(
|
||||
&mut self,
|
||||
k: &'static str,
|
||||
v: Box<dyn ParseExtensions<'a, Output = R, Error = E>>,
|
||||
) {
|
||||
self.map.insert(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R, E, const N: usize>
|
||||
From<
|
||||
[(
|
||||
&'static str,
|
||||
Box<dyn ParseExtensions<'a, Output = R, Error = E>>,
|
||||
); N],
|
||||
> for TagDispatchParser<'a, R, E>
|
||||
{
|
||||
fn from(
|
||||
p: [(
|
||||
&'static str,
|
||||
Box<dyn ParseExtensions<'a, Output = R, Error = E>>,
|
||||
); N],
|
||||
) -> Self {
|
||||
Self {
|
||||
map: p.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R, E> ParseExtensions<'a> for TagDispatchParser<'a, R, E> {
|
||||
type Output = R;
|
||||
|
||||
type Error = TagDispatchParseError<E>;
|
||||
|
||||
fn parse(
|
||||
&self,
|
||||
content: &'a str,
|
||||
span: crate::parse::Span,
|
||||
) -> core::result::Result<Self::Output, Self::Error> {
|
||||
let content = content.trim();
|
||||
let tag =
|
||||
content.split(char::is_whitespace).next().ok_or_else(|| {
|
||||
spanned(
|
||||
span.start,
|
||||
span.end,
|
||||
TagDispatchParseErrorBase::MissingTag,
|
||||
)
|
||||
})?;
|
||||
|
||||
let handler = self.map.get(tag).ok_or_else(|| {
|
||||
spanned(
|
||||
span.start,
|
||||
span.end,
|
||||
TagDispatchParseErrorBase::MissingParserFor(tag.into()),
|
||||
)
|
||||
})?;
|
||||
|
||||
let content = content.trim_start_matches(tag);
|
||||
|
||||
handler
|
||||
.parse(content, crate::parse::span(span.start, span.end))
|
||||
.map_err(|e| TagDispatchParseError::User(e))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue