You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
1.9 KiB
Rust
99 lines
1.9 KiB
Rust
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))
|
|
}
|
|
}
|