use crate::parser::Spanner;
pub fn is_space(c: char) -> bool {
c == ' ' || c == '\t' }
pub fn is_digit(c: char) -> bool {
c.is_ascii_digit()
}
pub struct StringParser<'b> {
reader: &'b str,
last: &'b str,
valid: bool,
}
pub fn strparse(reader: &str) -> StringParser {
StringParser::new(reader)
}
pub trait ParsePattern<'a> {
fn parse_pattern_strip_prefix(&mut self, reader: &'a str) -> Option<&'a str>;
fn parse_pattern_trim_start_matches(&mut self, reader: &'a str) -> &'a str;
fn parse_pattern_split_once(&mut self, reader: &'a str) -> Option<(&'a str, &'a str)>;
}
impl<'a> ParsePattern<'a> for char {
fn parse_pattern_strip_prefix(&mut self, reader: &'a str) -> Option<&'a str> {
reader.strip_prefix(*self)
}
fn parse_pattern_trim_start_matches(&mut self, reader: &'a str) -> &'a str {
reader.trim_start_matches(*self)
}
fn parse_pattern_split_once(&mut self, reader: &'a str) -> Option<(&'a str, &'a str)> {
reader.split_once(*self)
}
}
impl<'a> ParsePattern<'a> for &str {
fn parse_pattern_strip_prefix(&mut self, reader: &'a str) -> Option<&'a str> {
reader.strip_prefix(*self)
}
fn parse_pattern_trim_start_matches(&mut self, reader: &'a str) -> &'a str {
reader.trim_start_matches(*self)
}
fn parse_pattern_split_once(&mut self, reader: &'a str) -> Option<(&'a str, &'a str)> {
reader.split_once(*self)
}
}
impl<'a> ParsePattern<'a> for &[char] {
fn parse_pattern_strip_prefix(&mut self, reader: &'a str) -> Option<&'a str> {
reader.strip_prefix(*self)
}
fn parse_pattern_trim_start_matches(&mut self, reader: &'a str) -> &'a str {
reader.trim_start_matches(*self)
}
fn parse_pattern_split_once(&mut self, reader: &'a str) -> Option<(&'a str, &'a str)> {
reader.split_once(*self)
}
}
impl<'a, const N: usize> ParsePattern<'a> for &[char; N] {
fn parse_pattern_strip_prefix(&mut self, reader: &'a str) -> Option<&'a str> {
reader.strip_prefix(&self[..])
}
fn parse_pattern_trim_start_matches(&mut self, reader: &'a str) -> &'a str {
reader.trim_start_matches(&self[..])
}
fn parse_pattern_split_once(&mut self, reader: &'a str) -> Option<(&'a str, &'a str)> {
reader.split_once(&self[..])
}
}
impl<'a, F: FnMut(char) -> bool> ParsePattern<'a> for F {
fn parse_pattern_strip_prefix(&mut self, reader: &'a str) -> Option<&'a str> {
reader.strip_prefix(self)
}
fn parse_pattern_trim_start_matches(&mut self, reader: &'a str) -> &'a str {
reader.trim_start_matches(self)
}
fn parse_pattern_split_once(&mut self, reader: &'a str) -> Option<(&'a str, &'a str)> {
reader.split_once(self)
}
}
impl<'b> StringParser<'b> {
pub fn new(reader: &'b str) -> Self {
Self {
reader,
last: &reader[0..0],
valid: true,
}
}
pub fn accept<P: ParsePattern<'b>>(mut self, mut pattern: P) -> Self {
if self.valid {
self.last = self.reader;
if let Some(remaining) = pattern.parse_pattern_strip_prefix(self.reader) {
self.reader = remaining;
} else {
self.valid = false;
}
}
self
}
pub fn accept_or_end<P: ParsePattern<'b>>(self, pattern: P) -> Self {
if self.reader.is_empty() {
self
} else {
self.accept(pattern)
}
}
pub fn accepts_or_end(self, s: &[&str]) -> Self {
if self.reader.is_empty() {
self
} else {
self.accepts(s)
}
}
pub fn accepts(mut self, s: &[&str]) -> Self {
if self.valid {
self.last = self.reader;
for opt in s {
if let Some(remaining) = self.reader.strip_prefix(opt) {
self.reader = remaining;
return self
}
}
self.valid = false;
}
self
}
pub fn span<P: ParsePattern<'b>>(mut self, mut pattern: P, min: usize) -> Self {
if self.valid {
self.last = self.reader;
self.reader = pattern.parse_pattern_trim_start_matches(self.reader);
let len = self.last.len() - self.reader.len();
if min > 0 {
let count = self.last[0..len].chars().count();
self.valid = min <= count;
}
if self.valid {
self.reader = &self.last[len..];
}
}
self
}
pub fn span_max<P: ParsePattern<'b>>(mut self, mut pattern: P, min: usize, max: usize) -> Self {
if self.valid {
self.last = self.reader;
let max_bytes : usize = self.reader.chars().take(max).fold(0, |sum,x| sum + x.len_utf8());
self.reader = pattern.parse_pattern_trim_start_matches(&self.reader[0..max_bytes]);
let len = max_bytes - self.reader.len();
if min > 0 {
let count = self.last[0..len].chars().count();
self.valid = min <= count;
}
if self.valid {
self.reader = &self.last[len..];
}
}
self
}
pub fn spanner<S: Spanner>(mut self, spanner: &mut S) -> Self {
if self.valid {
self.last = self.reader;
if spanner.span(&mut self.reader).is_none() {
self.valid = false;
}
}
self
}
pub fn split<P: ParsePattern<'b>>(mut self, to: &mut &'b str, mut on: P) -> Self {
if self.valid {
self.last = self.reader;
if let Some((begin,remaining)) = on.parse_pattern_split_once(self.reader) {
*to = begin;
self.reader = remaining;
} else {
self.valid = false;
}
}
self
}
pub fn search<P: ParsePattern<'b>>(self, on: P) -> Self {
let mut to = "";
self.split(&mut to, on)
}
pub fn matched(self, to: &mut &'b str) -> Self {
if self.valid {
*to = &self.last[0..(self.last.len() - self.reader.len())];
}
self
}
pub fn matched_parse<T: std::str::FromStr>(mut self, to: &mut T) -> Self {
if self.valid {
let s = &self.last[0..(self.last.len() - self.reader.len())];
if let Ok(value) = s.parse() {
*to = value;
} else {
self.valid = false;
}
}
self
}
pub fn matched_fn<F: FnOnce(&'b str) -> bool>(mut self, to: F) -> Self {
if self.valid && !(to)(&self.last[0..(self.last.len() - self.reader.len())]) {
self.valid = false;
}
self
}
pub fn valid(self, reader: &mut &'b str) -> bool {
if self.valid {
*reader = self.reader;
}
self.valid
}
pub fn unskip(mut self) -> Self {
if self.valid {
self.reader = self.last;
self.last = &self.reader[0..0];
}
self
}
}