use core::marker::PhantomData;
use crate::{BBParser, Token};
pub type ParserRuleObjBox<'a, CustomTy> = Box<dyn ParserRuleObj<'a, CustomTy> + Send + 'a>;
pub enum ParserRuleAction {
CustomParser,
NoParse,
}
pub trait ParserRule<'a, CustomTy = ()>
where
CustomTy: Clone + 'a,
Self: Sized + Send + 'a,
{
const ACTION: ParserRuleAction;
fn transform_token(&self, token: &mut Token<'_, CustomTy>) -> bool;
#[cfg_attr(coverage_nightly, coverage(off))]
fn parse_custom<'b: 'a>(&mut self, _parser: &'b str) -> Token<'a, CustomTy> {
unimplemented!("Parse custom triggered, but not implemented.")
}
fn to_box(self) -> ParserRuleObjBox<'a, CustomTy> {
Box::new(ParserRuleImpl {
_customty: PhantomData,
_lifetime: PhantomData,
rule: self,
})
}
}
mod private {
pub trait Sealed {}
}
#[allow(private_bounds)]
pub trait ParserRuleObj<'a, CustomTy = ()>: private::Sealed
where
CustomTy: Clone,
{
fn action(&self) -> ParserRuleAction;
fn transform_token(&self, next: &mut Token<'_, CustomTy>) -> bool;
fn parse_custom<'b: 'a>(&mut self, _parser: &'b str) -> Token<'a, CustomTy>;
}
pub(super) struct ParserRuleImpl<'a, Rule, CustomTy>
where
Rule: ParserRule<'a, CustomTy> + ?Sized,
CustomTy: Clone + 'a,
{
pub _customty: PhantomData<CustomTy>,
pub _lifetime: PhantomData<&'a ()>,
pub rule: Rule,
}
unsafe impl<'a, Rule, CustomTy> Send for ParserRuleImpl<'a, Rule, CustomTy>
where
Rule: ParserRule<'a, CustomTy> + ?Sized + Send,
CustomTy: Clone,
{
}
impl<'a, Rule, CustomTy> private::Sealed for ParserRuleImpl<'a, Rule, CustomTy>
where
Rule: ParserRule<'a, CustomTy>,
CustomTy: Clone,
{
}
impl<'a, Rule, CustomTy> ParserRuleObj<'a, CustomTy> for ParserRuleImpl<'a, Rule, CustomTy>
where
Rule: ParserRule<'a, CustomTy>,
CustomTy: Clone,
{
fn action(&self) -> ParserRuleAction {
Rule::ACTION
}
fn transform_token(&self, next: &mut Token<'_, CustomTy>) -> bool {
self.rule.transform_token(next)
}
fn parse_custom<'b: 'a>(&mut self, parser: &'b str) -> Token<'a, CustomTy> {
self.rule.parse_custom(parser)
}
}
pub mod builtin {
use core::marker::PhantomData;
use crate::{parser::BBTag, Token, TokenKind};
use super::{ParserRule, ParserRuleAction};
pub struct NoParseRule<'a, CustomTy = ()> {
_custom_ty: PhantomData<CustomTy>,
tag_name: &'a str,
}
impl<'a, CustomTy> NoParseRule<'a, CustomTy> {
pub fn new(tag_name: &'a str) -> Self {
Self {
_custom_ty: PhantomData,
tag_name,
}
}
}
impl<'a, 'rule_life: 'a, CustomTy> ParserRule<'a, CustomTy> for NoParseRule<'rule_life, CustomTy>
where
CustomTy: Clone + Send + 'a,
{
const ACTION: ParserRuleAction = ParserRuleAction::NoParse;
fn transform_token(&self, next: &mut Token<'_, CustomTy>) -> bool {
if let TokenKind::CloseBBTag(BBTag { tag, .. }, ..) = next.kind {
tag.eq_ignore_ascii_case(self.tag_name)
} else {
false
}
}
}
}
impl<'a, CustomTy> BBParser<'a, CustomTy>
where
CustomTy: Clone + 'a,
{
pub fn push_rule<Rule>(&mut self, rule: Rule)
where
Rule: ParserRule<'a, CustomTy> + Send + 'a,
{
self.rule_stack.push(alloc::boxed::Box::new(
ParserRuleImpl::<'a, Rule, CustomTy> {
_customty: PhantomData,
_lifetime: PhantomData,
rule,
},
))
}
pub fn push_rule_obj(&mut self, rule: Box<dyn ParserRuleObj<'a, CustomTy> + Send + 'a>) {
self.rule_stack.push(rule)
}
}