oom-parsing 0.0.1

Lightweight Incremental Parser Generator inspired by Regular Expressions and Parsing Expression Grammars
Documentation
#![allow(unused, static_mut_refs)]
use std::cmp::{Eq, Ord, PartialEq, PartialOrd};
use std::collections::BTreeMap;
use std::fmt::{Debug, Display, Formatter};
use std::ops::Range;

use unique_pointer::UniquePointer;

use crate::{
    impl_matcher_for_ref, Ascii, Buffer, Match, Matcher, Position, Span, Special, StackRange, State,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Production {
    And(Vec<Production>),
    Ascii(Ascii),
    Atomic(Box<Production>),
    CompoundAtomic(Box<Production>),
    Literal(String),
    Named(String),
    Not(Box<Production>),
    OneOrMore(Box<Production>),
    Optional(Box<Production>),
    Or(Vec<Production>),
    Range(Range<char>),
    Special(Special),
    ZeroOrMore(Box<Production>),
}
impl Production {
    fn match_literal(
        &self,
        state: &mut State,
        input: &str,
        start: &Position,
        literal: &str,
    ) -> Option<Match> {
        if input.len() != literal.len() {
            None
        } else {
            (literal == input)
                .then_some((Production::Literal(literal.to_string()), start.span_to(&input)).into())
        }
    }

    fn match_named(
        &self,
        state: &mut State,
        input: &str,
        start: &Position,
        name: &str,
    ) -> Option<Match> {
        let matcher = state.matcher(name).expect("named matcher");
        if let Some(r#match) = matcher.is_match(state.as_mut(), input, start) {
            Some(
                Into::<Match>::into((self.clone(), self.span(start, input)))
                    .with_inner(vec![r#match]),
            )
        } else {
            None
        }
    }

    fn match_ascii(
        &self,
        state: &mut State,
        input: &str,
        start: &Position,
        ascii: &Ascii,
    ) -> Option<Match> {
        ascii.is_match(state.as_mut(), input, start)
    }

    fn match_range(
        &self,
        state: &mut State,
        input: &str,
        start: &Position,
        range: Range<char>,
    ) -> Option<Match> {
        self.match_or(
            state,
            input,
            start,
            &range
                .map(String::from)
                .map(|literal| Production::Literal(literal))
                .collect::<Vec<Production>>(),
        )
    }

    fn match_not(
        &self,
        state: &mut State,
        input: &str,
        start: &Position,
        matcher: &Production,
    ) -> Option<Match> {
        if input.is_empty() {
            return Some((self.clone(), self.span(start, input)).into());
        }
        let mut buffer = Buffer::new(input, false);
        if let Some(r#match) = buffer.produce(state.as_mut(), start, matcher) {
            None
        } else {
            Some((self.clone(), self.span(start, input)).into())
        }
    }

    fn match_optional(
        &self,
        state: &mut State,
        input: &str,
        start: &Position,
        matcher: &Production,
    ) -> Option<Match> {
        if input.is_empty() {
            return Some((self.clone(), self.span(start, input)).into());
        }
        let mut buffer = Buffer::new(input, false);
        if let Some(r#match) = buffer.produce(state.as_mut(), start, matcher) {
            Some(
                Into::<Match>::into((self.clone(), self.span(start, input)))
                    .with_inner(vec![r#match]),
            )
        } else {
            None
        }
    }

    fn match_special(
        &self,
        state: &mut State,
        input: &str,
        start: &Position,
        matcher: &Special,
    ) -> Option<Match> {
        if let Some(r#match) = matcher.is_match(state.as_mut(), input, start) {
            Some(
                Into::<Match>::into((self.as_production(), self.span(start, input)))
                    .with_inner(r#match.inner()),
            )
        } else {
            None
        }
    }

    fn match_atomic(
        &self,
        state: &mut State,
        input: &str,
        start: &Position,
        matcher: &Production,
    ) -> Option<Match> {
        if (*state).has_epsilon(input) {
            None
        } else {
            let mut buffer = Buffer::new(input, true);
            if let Some(r#match) = buffer.produce(state.as_mut(), start, matcher) {
                Some(
                    Into::<Match>::into((self.clone(), self.span(start, input)))
                        .with_inner(vec![r#match.clone()]),
                )
            } else {
                None
            }
        }
    }

    fn match_compound_atomic(
        &self,
        state: &mut State,
        input: &str,
        start: &Position,
        matcher: &Production,
    ) -> Option<Match> {
        if (*state).has_epsilon(input) {
            None
        } else {
            let mut buffer = Buffer::new(input, true);
            if let Some(r#match) = buffer.produce(state.as_mut(), start, matcher) {
                Some(
                    Into::<Match>::into((self.clone(), self.span(start, input)))
                        .with_inner(vec![r#match.clone()]),
                )
            } else {
                None
            }
        }
    }

    fn match_and(
        &self,
        state: &mut State,
        input: &str,
        start: &Position,
        matchers: &Vec<Production>,
    ) -> Option<Match> {
        let mut mindex = 0;
        let maxdex = matchers.len();
        if maxdex == mindex {
            return None;
        }
        let mut buffer = Buffer::new(input, false);
        let mut matches = Vec::new();
        for (index, matcher) in matchers.iter().enumerate() {
            if let Some(r#match) = buffer.produce(state.as_mut(), start, matcher) {
                matches.push(r#match);
            } else {
                return None;
            }
        }
        if matches.is_empty() {
            None
        } else {
            Some(Into::<Match>::into((self.clone(), self.span(start, input))).with_inner(matches))
        }
    }

    fn match_or(
        &self,
        state: &mut State,
        input: &str,
        start: &Position,
        matchers: &Vec<Production>,
    ) -> Option<Match> {
        for matcher in matchers {
            let mut buffer = Buffer::new(input, false);
            if let Some(r#match) = buffer.produce(state.as_mut(), start, matcher) {
                return Some(r#match.clone());
            }
        }
        None
    }

    fn match_one_or_more(
        &self,
        state: &mut State,
        input: &str,
        start: &Position,
        matcher: &Production,
    ) -> Option<Match> {
        let mut buffer = Buffer::new(input, false);
        let mut matches = Vec::new();
        while let Some(r#match) = buffer.produce(state.as_mut(), start, matcher) {
            matches.push(r#match);
        }

        if matches.len() > 0 {
            Some(Into::<Match>::into((self.clone(), start.span_to(input))).with_inner(matches))
        } else {
            None
        }
    }

    fn match_zero_or_more(
        &self,
        state: &mut State,
        input: &str,
        start: &Position,
        matcher: &Production,
    ) -> Option<Match> {
        if input.is_empty() {
            return Some((self.clone(), start.span_to(input)).into());
        }
        self.match_one_or_more(state, input, start, matcher)
    }
}

impl_matcher_for_ref!(Production);
impl Matcher for Production {
    fn is_match(&self, state: &mut State, input: &str, start: &Position) -> Option<Match> {
        match self {
            Production::And(matchers) => self.match_and(state, input, start, matchers),
            Production::Ascii(ascii) => self.match_ascii(state, input, start, ascii),
            Production::Atomic(matcher) => self.match_atomic(state, input, start, matcher.as_ref()),
            Production::CompoundAtomic(matcher) =>
                self.match_compound_atomic(state, input, start, matcher.as_ref()),
            Production::Literal(literal) => self.match_literal(state, input, start, literal),
            Production::Named(name) => self.match_named(state, input, start, name),
            Production::Not(matcher) => self.match_not(state, input, start, matcher),
            Production::OneOrMore(matcher) =>
                self.match_one_or_more(state, input, start, matcher.as_ref()),
            Production::Optional(matcher) => self.match_optional(state, input, start, matcher),
            Production::Or(matchers) => self.match_or(state, input, start, matchers),
            Production::Range(range) => self.match_range(state, input, start, range.clone()),
            Production::Special(matcher) => self.match_special(state, input, start, &matcher),
            Production::ZeroOrMore(matcher) =>
                self.match_zero_or_more(state, input, start, matcher.as_ref()),
        }
    }

    fn name(&self) -> &str {
        match self {
            Production::And(string) => "Production::And",
            Production::Ascii(ascii) => ascii.name(),
            Production::Atomic(atomic) => "Production::Atomic",
            Production::CompoundAtomic(compound_atomic) => "Production::CompoundAtomic",
            Production::Literal(string) => string.as_str(),
            Production::Named(name) => name.as_str(),
            Production::Not(string) => "Production::Not",
            Production::OneOrMore(string) => "Production::OneOrMore",
            Production::Optional(string) => "Production::Optional",
            Production::Or(string) => "Production::Or",
            Production::Range(range) =>
                format!("Production::Range({}..{})", range.start, range.end).leak(),
            Production::Special(string) => string.name(),
            Production::ZeroOrMore(string) => "Production::ZeroOrMore",
        }
    }

    fn to_str(&self) -> String {
        match self {
            Production::Atomic(string) => {
                format!("Production::Atomic({})", string.to_str())
            },
            Production::CompoundAtomic(string) => {
                format!("Production::CompoundAtomic({})", string.to_str())
            },
            Production::Ascii(string) => {
                format!("Production::Ascii({})", string.to_string())
            },
            Production::Not(matcher) => {
                format!("Production::Not({})", matcher.to_str())
            },
            Production::Optional(matcher) => {
                format!("Production::Optional({})", matcher.to_str())
            },
            Production::Literal(string) => {
                format!("Production::Literal({})", string.to_string())
            },
            Production::Range(range) => {
                format!("Production::Range({}..{})", range.start, range.end)
            },
            Production::Named(string) => {
                format!("Production::Named({})", string.to_string())
            },
            Production::Special(string) => {
                format!("Production::Special({})", string.name())
            },
            Production::And(items) => {
                format!(
                    "Production::And({})",
                    items
                        .iter()
                        .map(|matcher| matcher.to_str())
                        .collect::<Vec<String>>()
                        .join(", ")
                )
            },
            Production::Or(items) => {
                format!(
                    "Production::Or({})",
                    items
                        .iter()
                        .map(|matcher| matcher.to_str())
                        .collect::<Vec<String>>()
                        .join(", ")
                )
            },
            Production::OneOrMore(matcher) => {
                format!("Production::OneOrMore({})", matcher.as_ref().to_str())
            },
            Production::ZeroOrMore(matcher) => {
                format!("Production::ZeroOrMore({})", matcher.as_ref().to_str())
            },
        }
    }

    fn as_production(&self) -> Production {
        (*self).clone()
    }
}

impl From<&str> for Production {
    fn from(string: &str) -> Production {
        Production::Named(string.to_string())
    }
}
impl From<String> for Production {
    fn from(string: String) -> Production {
        Production::Named(string.clone())
    }
}
impl From<Special> for Production {
    fn from(matcher: Special) -> Production {
        Production::Special(matcher)
    }
}
impl From<Range<char>> for Production {
    fn from(range: Range<char>) -> Production {
        Production::Range(range)
    }
}

impl From<Ascii> for Production {
    fn from(ascii: Ascii) -> Production {
        Production::Ascii(ascii)
    }
}