diff --git a/src/input.rs b/src/input.rs index 1a35cd0..a304855 100644 --- a/src/input.rs +++ b/src/input.rs @@ -160,20 +160,29 @@ impl<'a> Input for &'a str { } } -pub trait InputMatch { - fn match_left(&self, pat: &'static Pat) -> Option; - fn match_right(&self, pat: &'static Pat) -> Option; +pub trait InputMatch { + fn match_left(&self, pat: &Pat) -> Option; + fn match_right(&self, pat: &Pat) -> Option; } -impl InputMatch<&'static [T]> for [T] { - fn match_left(&self, pat: &&[T]) -> Option { +impl, Pat: ?Sized> InputMatch<&'_ Pat> for I { + fn match_left(&self, &pat: &&Pat) -> Option { + self.match_left(pat) + } + fn match_right(&self, &pat: &&Pat) -> Option { + self.match_right(pat) + } +} + +impl InputMatch<[T]> for [T] { + fn match_left(&self, pat: &[T]) -> Option { if self.starts_with(pat) { Some(pat.len()) } else { None } } - fn match_right(&self, pat: &&[T]) -> Option { + fn match_right(&self, pat: &[T]) -> Option { if self.ends_with(pat) { Some(pat.len()) } else { @@ -201,15 +210,15 @@ impl InputMatch> for [T] { } } -impl InputMatch<&'static str> for str { - fn match_left(&self, pat: &&str) -> Option { +impl InputMatch for str { + fn match_left(&self, pat: &str) -> Option { if self.starts_with(pat) { Some(pat.len()) } else { None } } - fn match_right(&self, pat: &&str) -> Option { + fn match_right(&self, pat: &str) -> Option { if self.ends_with(pat) { Some(pat.len()) } else { diff --git a/src/parser.rs b/src/parser.rs index c76534a..7474e2d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -6,27 +6,27 @@ use std::collections::HashMap; use std::fmt; use std::hash::Hash; -pub struct Parser<'a, 'i, G: GrammarReflector, I: Input> { - state: &'a mut ParserState<'i, G, I>, +pub struct Parser<'a, 'i, G: GrammarReflector, I: Input, Pat> { + state: &'a mut ParserState<'i, G, I, Pat>, result: Range<'i>, remaining: Range<'i>, } -struct ParserState<'i, G: GrammarReflector, I: Input> { +struct ParserState<'i, G: GrammarReflector, I: Input, Pat> { forest: ParseForest<'i, G, I>, last_input_pos: Index<'i, Unknown>, - expected_pats: Vec<&'static dyn fmt::Debug>, + expected_pats: Vec, } #[derive(Debug)] -pub struct ParseError { +pub struct ParseError { pub at: A, - pub expected: Vec<&'static dyn fmt::Debug>, + pub expected: Vec, } -pub type ParseResult = Result>; +pub type ParseResult = Result>; -impl<'i, P, G, I: Input> Parser<'_, 'i, G, I> +impl<'i, P, G, I: Input, Pat> Parser<'_, 'i, G, I, Pat> where // FIXME(eddyb) these shouldn't be needed, as they are bounds on // `GrammarReflector::ParseNodeKind`, but that's ignored currently. @@ -36,8 +36,8 @@ where pub fn parse_with( grammar: G, input: I, - f: impl for<'i2> FnOnce(Parser<'_, 'i2, G, I>) -> Option>, - ) -> ParseResult> { + f: impl for<'i2> FnOnce(Parser<'_, 'i2, G, I, Pat>) -> Option>, + ) -> ParseResult> { ErasableL::indexing_scope(input.to_container(), |lifetime, input| { let range = Range(input.range()); let mut state = ParserState { @@ -99,7 +99,7 @@ where &'a mut self, result: Range<'i>, remaining: Range<'i>, - ) -> Parser<'a, 'i, G, I> { + ) -> Parser<'a, 'i, G, I, Pat> { // HACK(eddyb) enforce that `result` and `remaining` are inside `self`. assert_eq!(self.result, Range(self.remaining.frontiers().0)); let full_new_range = result.join(remaining.0).unwrap(); @@ -113,19 +113,19 @@ where } } - pub fn input_consume_left<'a, Pat: fmt::Debug>( + pub fn input_consume_left<'a, SpecificPat: Into>( &'a mut self, - pat: &'static Pat, - ) -> Option> + pat: SpecificPat, + ) -> Option> where - I::Slice: InputMatch, + I::Slice: InputMatch, { let start = self.remaining.first(); if start > self.state.last_input_pos { self.state.last_input_pos = start; self.state.expected_pats.clear(); } - match self.state.forest.input(self.remaining).match_left(pat) { + match self.state.forest.input(self.remaining).match_left(&pat) { Some(n) => { let (matching, after, _) = self.remaining.split_at(n); if n > 0 { @@ -140,22 +140,22 @@ where } None => { if start == self.state.last_input_pos { - self.state.expected_pats.push(pat); + self.state.expected_pats.push(pat.into()); } None } } } - pub fn input_consume_right<'a, Pat>( + pub fn input_consume_right<'a, SpecificPat>( &'a mut self, - pat: &'static Pat, - ) -> Option> + pat: SpecificPat, + ) -> Option> where - I::Slice: InputMatch, + I::Slice: InputMatch, { // FIXME(eddyb) implement error reporting support like in `input_consume_left` - match self.state.forest.input(self.remaining).match_right(pat) { + match self.state.forest.input(self.remaining).match_right(&pat) { Some(n) => { let (before, matching, _) = self.remaining.split_at(self.remaining.len() - n); Some(Parser { diff --git a/src/proc_macro.rs b/src/proc_macro.rs index 4a6a0f7..ba73e78 100644 --- a/src/proc_macro.rs +++ b/src/proc_macro.rs @@ -3,6 +3,8 @@ use crate::scannerless::Pat as SPat; pub use proc_macro2::{ Delimiter, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree, }; +use std::fmt; +use std::ops::Deref; use std::str::FromStr; pub type Context = crate::context::Context; @@ -46,7 +48,7 @@ pub fn builtin(cx: &mut Context) -> crate::Grammar { } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Pat(pub Vec>); +pub struct Pat>>(pub Pats); impl FromStr for Pat { type Err = LexError; @@ -72,6 +74,12 @@ impl From<&str> for Pat { } } +impl From for Pat { + fn from(pats: Pats) -> Self { + Pat(pats) + } +} + impl From> for Pat { fn from(pat: FlatTokenPat) -> Self { Pat(vec![pat]) @@ -100,7 +108,7 @@ pub enum FlatToken { Literal(Literal), } -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum FlatTokenPat> { Delim(char), Ident(Option), @@ -111,6 +119,51 @@ pub enum FlatTokenPat> { Literal, } +impl> fmt::Debug for FlatTokenPat { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + FlatTokenPat::Delim(c) | FlatTokenPat::Punct { ch: Some(c), .. } => { + write!(f, "\"{}\"", c) + } + FlatTokenPat::Ident(None) => f.write_str("IDENT"), + FlatTokenPat::Ident(Some(ident)) => write!(f, "\"{}\"", ident.as_ref()), + FlatTokenPat::Punct { ch: None, .. } => f.write_str("PUNCT"), + FlatTokenPat::Literal => f.write_str("LITERAL"), + } + } +} + +// FIXME(eddyb) can't use `Pats: AsRef<[FlatTokenPat]` as it doesn't constrain `S`. +impl, Pats: Deref]>> fmt::Debug for Pat { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.0[..] { + [] => f.write_str("\"\""), + [pat] => pat.fmt(f), + pats => { + let mut was_joint = true; + f.write_str("\"")?; + for pat in pats { + if !was_joint { + f.write_str(" ")?; + } + match pat { + FlatTokenPat::Punct { ch: Some(c), joint } => { + write!(f, "{}", c)?; + was_joint = *joint == Some(true); + } + FlatTokenPat::Ident(Some(ident)) => { + write!(f, "\"{}\"", ident.as_ref())?; + was_joint = false; + } + _ => unreachable!(), + } + } + f.write_str("\"") + } + } + } +} + impl FlatToken { pub fn span(&self) -> Span { match self { diff --git a/src/proc_macro_input.rs b/src/proc_macro_input.rs index 53d6fa2..f7a0c77 100644 --- a/src/proc_macro_input.rs +++ b/src/proc_macro_input.rs @@ -52,8 +52,8 @@ impl Input for TokenStream { } } -impl InputMatch<&'static [FlatTokenPat<&'static str>]> for [FlatToken] { - fn match_left(&self, &pat: &&[FlatTokenPat<&str>]) -> Option { +impl InputMatch<[FlatTokenPat<&'_ str>]> for [FlatToken] { + fn match_left(&self, pat: &[FlatTokenPat<&str>]) -> Option { if self .iter() .zip(pat) @@ -66,7 +66,7 @@ impl InputMatch<&'static [FlatTokenPat<&'static str>]> for [FlatToken] { None } } - fn match_right(&self, &pat: &&[FlatTokenPat<&str>]) -> Option { + fn match_right(&self, pat: &[FlatTokenPat<&str>]) -> Option { if self .iter() .zip(pat) diff --git a/src/scannerless.rs b/src/scannerless.rs index 0f0edc3..4139177 100644 --- a/src/scannerless.rs +++ b/src/scannerless.rs @@ -1,15 +1,35 @@ use crate::rule::{MatchesEmpty, MaybeKnown}; use std::char; +use std::fmt; use std::ops::{self, Bound, RangeBounds}; pub type Context = crate::context::Context>; -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Pat { String(S), Range(C, C), } +impl fmt::Debug for Pat { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Pat::String(s) => s.fmt(f), + &Pat::Range(start, end) => { + if start != '\0' { + start.fmt(f)?; + } + f.write_str("..")?; + if end != char::MAX { + f.write_str("=")?; + end.fmt(f)?; + } + Ok(()) + } + } + } +} + impl<'a, C> From<&'a str> for Pat<&'a str, C> { fn from(s: &'a str) -> Self { Pat::String(s)