use core::{cmp::min, fmt, fmt::Debug, fmt::Display, hash::Hash, ops::Deref, str::FromStr};
use regex::Regex;
use self::parsable::Exact;
use super::*;
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Error(Diagnostic);
impl Deref for Error {
type Target = Diagnostic;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Error {
pub fn new(span: Span, message: impl ToString) -> Error {
Error(Diagnostic::new(
DiagnosticLevel::Error,
span,
message,
Option::<String>::None,
Vec::new(),
))
}
pub fn expected(span: Span, expected: impl Display) -> Error {
Error(Diagnostic::new(
DiagnosticLevel::Error,
span,
format!("expected `{expected}`"),
Option::<String>::None,
Vec::new(),
))
}
}
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ParseStream {
source: Rc<Source>,
pub position: usize,
}
impl ParseStream {
pub fn source(&self) -> &Rc<Source> {
&self.source
}
pub fn current_span(&self) -> Span {
Span::new(
self.source.clone(),
self.position..(min(self.source().len(), self.position + 1)),
)
}
pub fn remaining_span(&self) -> Span {
Span::new(self.source.clone(), self.position..self.source.len())
}
pub fn parse<T: Parsable>(&mut self) -> Result<T> {
T::parse(self)
}
pub fn parse_value<T: Parsable>(&mut self, value: T) -> Result<T> {
T::parse_value(value, self)
}
pub fn parse_regex(&mut self, reg: impl Pattern) -> Result<Exact> {
let reg = reg.to_regex();
match reg.find(self.remaining().as_str()) {
Some(m) => {
if m.start() > 0 {
return Err(Error::new(
self.current_span(),
format!("expected match for `{reg}`"),
));
}
let start_position = self.position;
self.position += m.as_str().len();
Ok(Exact::new(Span::new(
self.source.clone(),
start_position..self.position,
)))
}
None => Err(Error::new(
self.current_span(),
format!("expected match for `{reg}`"),
)),
}
}
pub fn peek_regex(&self, reg: Regex) -> bool {
self.fork().parse_regex(reg).is_ok()
}
pub fn parse_str(&mut self, value: impl ToString) -> Result<Exact> {
self.parse_value(Exact::from(value))
}
pub fn parse_istr(&mut self, value: impl ToString) -> Result<Exact> {
let text: IndexedString = value.to_string().to_lowercase().into();
let remaining_lower = self.remaining().to_lowercase();
if remaining_lower.starts_with(&text) {
let span = self.consume(text.len())?;
return Ok(Exact::new(span));
}
let prefix = common_prefix(&text, &remaining_lower);
let expected = &text.slice(prefix.len()..);
let span = Span::new(
self.source.clone(),
(self.position + prefix.len())..(self.position + text.len()),
);
self.position += prefix.len();
Err(Error::expected(span, expected))
}
pub fn peek_str(&self, s: impl AsRef<str>) -> bool {
self.remaining().starts_with(s.as_ref())
}
pub fn peek_istr(&self, s: impl ToString) -> bool {
self.remaining()
.to_lowercase()
.starts_with(s.to_string().to_lowercase())
}
pub fn parse_any_value_of<T: Parsable, const N: usize>(&mut self, values: [T; N]) -> Result<T> {
for value in &values {
if self.peek_value(value.clone()) {
return self.parse_value(value.clone());
}
}
Err(Error::new(
self.current_span(),
format!(
"expected one of {}",
values
.into_iter()
.map(|v| format!("`{}`", v.span().source_text()))
.collect::<Vec<String>>()
.join(", ")
),
))
}
pub fn parse_any_str_of<const N: usize>(
&mut self,
values: [impl ToString; N],
) -> Result<(Exact, usize)> {
for (i, s) in values.iter().enumerate() {
let s = s.to_string();
if self.peek_str(&s) {
return Ok((self.parse_str(s)?, i));
}
}
Err(Error::new(
self.current_span(),
format!(
"expected one of {}",
values
.into_iter()
.map(|s| format!("`{}`", s.to_string()))
.collect::<Vec<String>>()
.join(", ")
),
))
}
pub fn parse_any_istr_of<const N: usize>(
&mut self,
values: [impl ToString; N],
) -> Result<(Exact, usize)> {
for (i, s) in values.iter().enumerate() {
let s = s.to_string();
if self.peek_istr(&s) {
return Ok((self.parse_istr(s)?, i));
}
}
Err(Error::new(
self.current_span(),
format!(
"expected one of {}",
values
.into_iter()
.map(|s| format!("`{}`", s.to_string()))
.collect::<Vec<String>>()
.join(", ")
),
))
}
pub fn peek_any_value_of<T: Parsable, const N: usize>(&self, values: [T; N]) -> bool {
self.fork().parse_any_value_of(values).is_ok()
}
pub fn peek_any_str_of<const N: usize>(&self, values: [impl ToString; N]) -> bool {
self.fork().parse_any_str_of(values).is_ok()
}
pub fn peek_any_istr_of<const N: usize>(&self, values: [impl ToString; N]) -> bool {
self.fork().parse_any_istr_of(values).is_ok()
}
pub fn remaining(&self) -> IndexedSlice<'_> {
self.source.slice(self.position..)
}
pub fn fork(&self) -> Self {
self.clone()
}
pub fn consume(&mut self, num_chars: usize) -> Result<Span> {
if self.remaining().len() < num_chars {
return Err(Error::new(
self.remaining_span(),
format!(
"expected at least {num_chars} more characters, found {}",
self.remaining().len()
),
));
}
let position = self.position;
self.position += num_chars;
Ok(Span::new(self.source.clone(), position..self.position))
}
pub fn consume_remaining(&mut self) -> Span {
let span = self.remaining_span();
self.position = self.source.len();
span
}
pub fn next_char(&self) -> Result<char> {
if self.remaining().is_empty() {
return Err(Error::new(self.current_span(), "unexpected end of input"));
}
let c = self
.current_span()
.source_text()
.chars()
.first()
.cloned()
.unwrap();
Ok(c)
}
pub fn parse_char(&mut self) -> Result<char> {
let c = self.next_char()?;
self.position += 1;
Ok(c)
}
pub fn next_digit(&self) -> Result<u8> {
Ok(match self.next_char()? {
'0' => 0,
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
'6' => 6,
'7' => 7,
'8' => 8,
'9' => 9,
_ => return Err(Error::new(self.current_span(), "expected digit (0-9)")),
})
}
pub fn parse_digit(&mut self) -> Result<u8> {
let digit = self.next_digit()?;
self.position += 1;
Ok(digit)
}
pub fn next_alpha(&self) -> Result<char> {
let c = self.next_char()?;
if !c.is_ascii_alphabetic() {
return Err(Error::new(
self.current_span(),
"expected alphabetic (A-Z|a-z)",
));
}
Ok(c)
}
pub fn parse_alpha(&mut self) -> Result<char> {
let c = self.next_alpha()?;
self.position += 1;
Ok(c)
}
pub fn peek<T: Peekable>(&self) -> bool {
T::peek(self)
}
pub fn peek_value<T: Peekable>(&self, value: T) -> bool {
T::peek_value(value, self)
}
}
impl<S: Into<Source>> From<S> for ParseStream {
fn from(value: S) -> Self {
ParseStream {
source: Rc::new(value.into()),
position: 0,
}
}
}
pub fn parse<T: Parsable>(stream: impl Into<ParseStream>) -> Result<T> {
T::parse(&mut stream.into())
}
pub fn common_prefix(s1: impl IndexedStr, s2: impl IndexedStr) -> IndexedString {
let mut result = String::new();
for (b1, b2) in s1.chars().iter().zip(s2.chars()) {
if b1 == b2 {
result.push(*b1);
} else {
break;
}
}
IndexedString::from_string(result)
}
pub trait Parsable:
Clone + Debug + PartialEq + Eq + Hash + Display + Spanned + FromStr + Peekable
{
fn parse(stream: &mut ParseStream) -> Result<Self>;
fn parse_value(value: Self, stream: &mut ParseStream) -> Result<Self> {
let s = value.span();
let text = s.source_text();
if stream.remaining().starts_with(&text) {
return stream.parse();
}
let prefix = common_prefix(&text, stream.remaining());
let expected = text.slice(prefix.len()..);
let span = Span::new(
stream.source.clone(),
(stream.position + prefix.len())..(stream.position + text.len()),
);
stream.position += prefix.len();
Err(Error::expected(span, expected))
}
fn unparse(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.span().source_text())
}
}
impl<T: Parsable> Peekable for T {
fn peek(stream: &ParseStream) -> bool {
stream.fork().parse::<Self>().is_ok()
}
fn peek_value(value: Self, stream: &ParseStream) -> bool {
stream.fork().parse_value(value).is_ok()
}
}
pub trait Peekable {
fn peek(stream: &ParseStream) -> bool;
fn peek_value(value: Self, stream: &ParseStream) -> bool;
}
impl Peekable for &str {
fn peek(_: &ParseStream) -> bool {
true
}
fn peek_value(value: Self, stream: &ParseStream) -> bool {
stream.remaining().to_string().starts_with(value)
}
}
impl Peekable for String {
fn peek(_: &ParseStream) -> bool {
true
}
fn peek_value(value: Self, stream: &ParseStream) -> bool {
stream.remaining().starts_with(&value)
}
}
impl Peekable for &String {
fn peek(_: &ParseStream) -> bool {
true
}
fn peek_value(value: Self, stream: &ParseStream) -> bool {
stream.remaining().starts_with(value)
}
}
impl Peekable for IndexedString {
fn peek(_: &ParseStream) -> bool {
true
}
fn peek_value(value: Self, stream: &ParseStream) -> bool {
stream.remaining().starts_with(&value)
}
}
impl Peekable for &IndexedString {
fn peek(_: &ParseStream) -> bool {
true
}
fn peek_value(value: Self, stream: &ParseStream) -> bool {
stream.remaining().starts_with(value)
}
}
impl<'a> Peekable for IndexedSlice<'a> {
fn peek(_: &ParseStream) -> bool {
true
}
fn peek_value(value: Self, stream: &ParseStream) -> bool {
stream.remaining().starts_with(value)
}
}
impl<'a> Peekable for &'a IndexedSlice<'a> {
fn peek(_: &ParseStream) -> bool {
true
}
fn peek_value(value: Self, stream: &ParseStream) -> bool {
stream.remaining().starts_with(value)
}
}
pub trait Pattern: Sized {
fn to_regex(self) -> Regex {
self.try_to_regex().unwrap()
}
fn try_to_regex(self) -> core::result::Result<Regex, regex::Error>;
}
impl Pattern for Regex {
fn try_to_regex(self) -> core::result::Result<Regex, regex::Error> {
Ok(self)
}
}
impl Pattern for &Regex {
fn try_to_regex(self) -> core::result::Result<Regex, regex::Error> {
Ok(self.clone())
}
}
impl Pattern for &str {
fn try_to_regex(self) -> core::result::Result<Regex, regex::Error> {
Regex::new(self)
}
}
impl Pattern for String {
fn try_to_regex(self) -> core::result::Result<Regex, regex::Error> {
Regex::new(&self)
}
}
#[test]
fn test_parse_digit() {
let mut stream = ParseStream::from("0183718947");
assert_eq!(stream.parse_digit().unwrap(), 0);
assert_eq!(stream.parse_digit().unwrap(), 1);
assert_eq!(stream.parse_digit().unwrap(), 8);
assert_eq!(stream.parse_digit().unwrap(), 3);
assert_eq!(stream.parse_digit().unwrap(), 7);
assert_eq!(stream.parse_digit().unwrap(), 1);
assert_eq!(stream.parse_digit().unwrap(), 8);
assert_eq!(stream.parse_digit().unwrap(), 9);
assert_eq!(stream.parse_digit().unwrap(), 4);
assert_eq!(stream.parse_digit().unwrap(), 7);
stream.parse_digit().unwrap_err();
let mut stream = ParseStream::from("hey");
stream.parse_digit().unwrap_err();
}
#[test]
fn test_peeking() {
use parsable::*;
let mut stream = ParseStream::from("hey 48734 is cool");
assert!(stream.peek::<String>());
assert!(stream.peek::<&str>());
assert!(stream.peek::<&String>());
assert!(!stream.peek::<Nothing>());
assert!(stream.peek::<Everything>());
assert_eq!(
stream.parse_value(Exact::from("hey ")).unwrap().to_string(),
"hey "
);
}
#[test]
fn test_parse_any_value_of() {
use parsable::*;
let mut stream = ParseStream::from("this 99.2 is really cool");
assert!(stream.peek_value(Exact::from("this")));
assert!(stream.peek_value("this"));
let parsed = stream
.parse_any_value_of([
Exact::from("yo"),
Exact::from("this"),
Exact::from("this 99.2"),
])
.unwrap();
assert_eq!(parsed.to_string(), "this");
assert!(!stream.peek_value(Exact::from(" 998")));
assert!(stream.peek_any_str_of([" 998", " 99.2"]));
assert!(stream.peek_any_istr_of([" 99.2 z", " 99.2 IS"]));
assert!(stream.parse_any_istr_of([" asdf", " 99.2 iS"]).unwrap().1 == 1);
}
#[test]
fn test_str_peeking_and_parsing() {
let mut stream = ParseStream::from("here ARe 222.44 some cool things");
assert!(stream.peek_str("here"));
assert!(stream.peek_istr("HeRe"));
assert!(!stream.peek_str("HeRe"));
let parsed = stream.parse_istr("HERe ").unwrap();
assert_eq!(parsed.to_string(), "here ");
assert!(!stream.peek_str("are"));
assert!(stream.peek_istr("arE"));
let parsed = stream.parse_str("ARe ").unwrap();
assert_eq!(parsed.span().source_text(), "ARe ");
}
#[test]
fn test_regex_parsing() {
let mut stream = ParseStream::from("$33.29");
let parsed = stream
.parse_regex(r"(?i)\$?-?\d{1,3}(?:,\d{3})*(?:\.\d{1,2})?")
.unwrap();
assert_eq!(parsed.span().source_text(), "$33.29");
let mut stream = ParseStream::from("$33.29");
let parsed = stream
.parse_regex(r"^(?i)\$?-?\d{1,3}(?:,\d{3})*(?:\.\d{1,2})?$")
.unwrap();
assert_eq!(parsed.span().source_text(), "$33.29");
let mut stream = ParseStream::from("asdf33.29");
let parsed = stream
.parse_regex(r"^(?i)\$?-?\d{1,3}(?:,\d{3})*(?:\.\d{1,2})?$")
.unwrap_err();
assert!(parsed.to_string().contains("expected match for"));
let mut stream = ParseStream::from("hey what $33.29");
let parsed = stream
.parse_regex(r"(?i)\$?-?\d{1,3}(?:,\d{3})*(?:\.\d{1,2})?")
.unwrap_err();
assert!(parsed.to_string().contains("expected match for"));
}
#[test]
fn test_multibyte_parsing() {
let mut stream = ParseStream::from("你好, 世界");
assert!(stream.peek_value("你"));
let parsed = stream.parse_istr("你好").unwrap();
assert_eq!(parsed.to_string(), "你好");
assert_ne!(stream.source().len(), stream.source().byte_len());
assert!(stream.peek_value(","));
}