use super::position::Position;
use super::syllable::SyllableCondition;
pub trait TokenLike: Clone + PartialEq + std::fmt::Debug {
fn is_pipe(&self) -> bool;
fn is_ampersand(&self) -> bool;
fn is_exclamation(&self) -> bool;
fn is_group_start(&self) -> bool;
fn is_group_end(&self) -> bool;
fn is_hash(&self) -> bool;
fn is_star(&self) -> bool;
fn is_plus(&self) -> bool;
fn is_question(&self) -> bool;
fn is_brace_start(&self) -> bool;
fn is_eof(&self) -> bool;
fn is_if_keyword(&self) -> bool;
fn as_syllable_condition(&self) -> Option<SyllableCondition>;
fn can_start_primary(&self) -> bool;
}
pub trait LexerLike {
type Token: TokenLike;
type Error;
fn peek(&mut self) -> Result<&Self::Token, Self::Error>;
fn advance(&mut self) -> Result<Self::Token, Self::Error>;
fn position(&self) -> Position;
}
pub trait SyllableParser {
type Lexer: LexerLike;
type Error;
fn lexer_mut(&mut self) -> &mut Self::Lexer;
fn make_unexpected_token_error(
&self,
expected: &str,
found: &<Self::Lexer as LexerLike>::Token,
position: Position,
) -> Self::Error;
fn from_lexer_error(&self, err: <Self::Lexer as LexerLike>::Error) -> Self::Error;
}
pub trait ContextParser: SyllableParser {
type Pattern;
fn parse_pattern_for_context(&mut self) -> Result<Self::Pattern, Self::Error>;
fn can_start_context_expr(&mut self) -> Result<bool, Self::Error>;
}
pub trait GrammarParser: SyllableParser {
type Pattern;
fn parse_primary(&mut self) -> Result<Self::Pattern, Self::Error>;
fn can_start_primary(&mut self) -> Result<bool, Self::Error>;
fn build_empty() -> Self::Pattern;
fn build_alternation(left: Self::Pattern, right: Self::Pattern) -> Self::Pattern;
fn build_concat(left: Self::Pattern, right: Self::Pattern) -> Self::Pattern;
fn build_star(inner: Self::Pattern) -> Self::Pattern;
fn build_plus(inner: Self::Pattern) -> Self::Pattern;
fn build_optional(inner: Self::Pattern) -> Self::Pattern;
fn build_repetition(inner: Self::Pattern, min: usize, max: Option<usize>) -> Self::Pattern;
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, PartialEq)]
enum MockToken {
Pipe,
Monosyllable,
Char(char),
}
impl TokenLike for MockToken {
fn is_pipe(&self) -> bool {
matches!(self, MockToken::Pipe)
}
fn is_ampersand(&self) -> bool {
false
}
fn is_exclamation(&self) -> bool {
false
}
fn is_group_start(&self) -> bool {
false
}
fn is_group_end(&self) -> bool {
false
}
fn is_hash(&self) -> bool {
false
}
fn is_star(&self) -> bool {
false
}
fn is_plus(&self) -> bool {
false
}
fn is_question(&self) -> bool {
false
}
fn is_brace_start(&self) -> bool {
false
}
fn is_eof(&self) -> bool {
false
}
fn is_if_keyword(&self) -> bool {
false
}
fn as_syllable_condition(&self) -> Option<SyllableCondition> {
match self {
MockToken::Monosyllable => Some(SyllableCondition::Monosyllable),
_ => None,
}
}
fn can_start_primary(&self) -> bool {
matches!(self, MockToken::Char(_))
}
}
#[test]
fn test_mock_token_like() {
let pipe = MockToken::Pipe;
assert!(pipe.is_pipe());
assert!(!pipe.is_ampersand());
let mono = MockToken::Monosyllable;
assert_eq!(
mono.as_syllable_condition(),
Some(SyllableCondition::Monosyllable)
);
let char_tok = MockToken::Char('a');
assert!(char_tok.can_start_primary());
assert_eq!(char_tok.as_syllable_condition(), None);
}
}