use std::sync::Arc;
use crate::*;
#[derive(Debug, Clone, Copy)]
enum StartIdx {
Init(usize),
Skiped(usize),
}
impl std::ops::Deref for StartIdx {
type Target = usize;
fn deref(&self) -> &Self::Target {
match self {
StartIdx::Init(idx) | StartIdx::Skiped(idx) => idx,
}
}
}
impl std::ops::DerefMut for StartIdx {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
StartIdx::Init(idx) | StartIdx::Skiped(idx) => idx,
}
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct ParserState {
start: StartIdx,
idx: usize,
}
impl ParserState {
pub(crate) fn fork(&self) -> ParserState {
Self {
start: StartIdx::Init(self.idx),
idx: self.idx,
}
}
pub(crate) fn force_sync(mut self, tmp: &ParserState) -> Self {
self.idx = tmp.idx;
self.start = match (self.start, tmp.start) {
(StartIdx::Init(..), StartIdx::Skiped(idx)) => StartIdx::Skiped(idx),
(idx, ..) => StartIdx::Skiped(*idx),
};
self
}
pub(crate) fn sync_with<T, E>(self, tmp: &ParserState, result: &Result<T, E>) -> Self {
if result.is_ok() {
self.force_sync(tmp)
} else {
self
}
}
}
#[cfg(feature = "parser_calling_tree")]
pub mod calling_tree {
use crate::{ParseErrorKind, Span};
#[derive(Clone, Copy)]
pub enum Calling {
Start,
Success(Span),
Err(ParseErrorKind, Span),
}
impl Calling {
pub fn new<P>(result: &Result<P, super::ParseError>, span: Span) -> Self {
match result {
Ok(_) => Self::Success(span),
Err(e) => Self::Err(e.kind(), span),
}
}
#[must_use]
pub fn is_start(&self) -> bool {
matches!(self, Self::Start)
}
}
impl std::fmt::Debug for Calling {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Start => write!(f, "Start: "),
Self::Success(span) => write!(f, "Success<{span:?}>"),
Self::Err(arg0, span) => write!(f, "{:?}<{span:?}>", arg0),
}
}
}
#[derive(Debug, Clone)]
enum Record {
Normal { pu: &'static str, call: Calling },
Custom { msg: String },
}
impl Record {
fn print(&self, depth: &mut usize, f: &mut impl std::fmt::Write) -> std::fmt::Result {
match self {
Record::Normal { pu, call } => {
if call.is_start() {
for _ in 0..*depth {
write!(f, " ")?;
}
*depth += 1;
writeln!(f, "{:?}{}", call, pu)
} else {
*depth -= 1;
for _ in 0..*depth {
write!(f, " ")?;
}
writeln!(f, "{:?} {}", call, pu)
}
}
Record::Custom { msg } => writeln!(f, "{msg}"),
}
}
}
#[derive(Default, Debug, Clone)]
pub struct CallingTree {
records: Vec<Record>,
}
impl CallingTree {
pub fn record_normal<P>(&mut self, call: Calling) {
self.records.push(Record::Normal {
pu: std::any::type_name::<P>(),
call,
});
}
pub fn record_custom(&mut self, msg: impl std::fmt::Display) {
self.records.push(Record::Custom {
msg: msg.to_string(),
});
}
}
impl std::fmt::Display for CallingTree {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut depth = 0;
for record in &self.records {
record.print(&mut depth, f)?;
}
Ok(())
}
}
}
#[derive(Debug)]
pub struct Parser<S: Source> {
buffer: Arc<dyn AsBuffer<S>>,
state: ParserState,
#[cfg(feature = "parser_calling_tree")]
calling_tree: calling_tree::CallingTree,
}
impl<S: Source> WithSpan for Parser<S> {
fn get_span(&self) -> Span {
if self.start_idx() == self.current_idx() {
Span::new(self.start_idx(), self.start_idx() + 1)
} else {
Span::new(self.start_idx(), self.current_idx())
}
}
}
impl<S: Source> WithBufName for Parser<S> {
fn buf_name(&self) -> &Arc<str> {
self.buffer.buf_name()
}
}
impl<S: Source> Parser<S> {
pub fn new(src: Arc<dyn AsBuffer<S>>) -> Parser<S> {
Parser {
buffer: src,
state: ParserState {
start: StartIdx::Init(0),
idx: 0,
},
#[cfg(feature = "parser_calling_tree")]
calling_tree: Default::default(),
}
}
#[inline]
pub fn select(&self, span: Span) -> &[S] {
&self.buffer.as_ref().as_ref()[span.start..span.end]
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Option<&S> {
let next = self.buffer.as_ref().as_ref().get(self.current_idx())?;
self.state.idx += 1;
Some(next)
}
pub fn next_if<C>(&mut self, cond: C) -> Option<&S>
where
C: FnOnce(&S) -> bool,
{
if self.peek().is_some_and(cond) {
self.next()
} else {
None
}
}
#[inline]
pub fn peek(&self) -> Option<&S> {
let slice = self.buffer.as_ref().as_ref();
slice.get(self.current_idx())
}
#[inline]
pub(crate) fn start_idx(&self) -> usize {
*self.state.start
}
#[inline]
pub(crate) fn current_idx(&self) -> usize {
self.state.idx
}
#[inline]
pub fn start_taking(&mut self) {
if let StartIdx::Init(..) = self.state.start {
self.state.start = StartIdx::Skiped(self.current_idx());
}
}
#[inline]
#[cfg(feature = "parser_calling_tree")]
pub fn calling_tree(&self) -> &calling_tree::CallingTree {
&self.calling_tree
}
pub fn buffer(&self) -> &Arc<dyn AsBuffer<S>> {
&self.buffer
}
pub fn once_no_try<P, F>(&mut self, parser: F) -> Result<P, ParseError>
where
F: FnOnce(&mut Parser<S>) -> Result<P, ParseError>,
{
#[cfg(feature = "parser_calling_tree")]
self.calling_tree
.record_normal::<P>(calling_tree::Calling::Start);
let result = parser(self);
#[cfg(feature = "parser_calling_tree")]
self.calling_tree
.record_normal::<P>(calling_tree::Calling::new(&result, self.get_span()));
#[cfg_attr(not(feature = "parser_calling_tree"), allow(clippy::let_and_return))]
result
}
pub fn once<P, F>(&mut self, parser: F) -> Result<P, ParseError>
where
F: FnOnce(&mut Parser<S>) -> Result<P, ParseError>,
{
let state = self.state;
self.state = self.state.fork();
let result = self.once_no_try::<P, _>(parser);
self.state = state.sync_with(&self.state, &result);
result
}
#[inline]
pub fn parse<P: ParseUnit<S>>(&mut self) -> ParseResult<P, S> {
self.once(P::parse)
}
#[inline]
pub fn r#match<P>(&mut self, rhs: P) -> Result<P::Left, ParseError>
where
P: ReverseParseUnit<S>,
{
self.once(|p| rhs.reverse_parse(p))
}
}
pub struct Try<'p, P: ParseUnit<S>, S: Source> {
parser: &'p mut Parser<S>,
state: Option<ParseResult<P, S>>,
}
impl<'p, P: ParseUnit<S>, S: Source> Try<'p, P, S> {
pub fn new(parser: &'p mut Parser<S>) -> Self {
Self {
parser,
state: None,
}
}
pub fn or_try<F>(mut self, parser: F) -> Self
where
F: FnOnce(&mut Parser<S>) -> Result<P::Result, ParseError>,
{
let is_unmatch = self.state.as_ref().is_some_and(|result| {
result
.as_ref()
.is_err_and(|e| e.kind() == ParseErrorKind::Unmatch)
});
if self.state.is_none() || is_unmatch {
let state = self.parser.once(parser);
self.state = Some(state);
}
self
}
pub fn or_error(mut self, reason: impl ToString) -> Self {
self.state = self.state.or_else(|| Some(self.parser.throw(reason)));
self
}
pub fn finish(self) -> ParseResult<P, S> {
self.state.unwrap()
}
}