diff --git a/src/lib.rs b/src/lib.rs index 977a72a..6ab56ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +#[macro_use] pub mod matching; pub mod tokenizing; mod utils; diff --git a/src/matching/matchers.rs b/src/matching/matchers.rs index e69de29..7242d6f 100644 --- a/src/matching/matchers.rs +++ b/src/matching/matchers.rs @@ -0,0 +1,56 @@ +use crate::do_match; +use crate::matching::MatchResult; +use crate::tokenizing::{Token, TokenReader}; +use std::any::TypeId; + +/// Matches exactly one token +pub async fn match_one(reader: &mut TokenReader) -> MatchResult<&Token> { + let token = if reader.peek_is::() { + reader.consume() + } else { + return Ok(None); + }; + + Ok(Some(token)) +} + +/// Matches many tokens at once by TypeId +pub async fn match_many<'a, I: IntoIterator>( + reader: &mut TokenReader, + ids: I, +) -> MatchResult<&Token> { + for id in ids { + if &reader.peek().inner_type_id() == id { + return Ok(Some(reader.consume())); + } + } + + Ok(None) +} + +/// Matches many tokens at once by TypeId +pub async fn match_many_mul<'a, I: IntoIterator + Clone>( + reader: &mut TokenReader, + ids: I, +) -> MatchResult { + let mut count = 0; + while match_many(reader, ids.clone()).await?.is_some() { + count += 1; + } + + Ok(Some(count)) +} + +/// Matches many tokens at least once by TypeId +pub async fn match_many_mul_plus<'a, I: IntoIterator + Clone>( + reader: &mut TokenReader, + ids: I, +) -> MatchResult { + let count = do_match!(match_many_mul(reader, ids)); + + if count > 0 { + Ok(Some(count)) + } else { + Ok(None) + } +} diff --git a/src/matching/mod.rs b/src/matching/mod.rs index e69de29..e16c6ed 100644 --- a/src/matching/mod.rs +++ b/src/matching/mod.rs @@ -0,0 +1,16 @@ +use crate::TapeResult; + +mod matchers; + +pub type MatchResult = TapeResult>; +pub use matchers::*; + +#[macro_export] +macro_rules! do_match { + ($matcher:expr) => { + match $matcher.await? { + Some(inner) => inner, + None => return Ok(None), + } + }; +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 016cbd6..b2990a7 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,4 +1,5 @@ mod test_input; mod test_lexer; +mod test_matching; mod test_token; mod test_token_reader; diff --git a/src/tests/test_matching.rs b/src/tests/test_matching.rs new file mode 100644 index 0000000..e776bdd --- /dev/null +++ b/src/tests/test_matching.rs @@ -0,0 +1,70 @@ +use crate::do_match; +use crate::matching::{match_many, match_many_mul, match_many_mul_plus, match_one, MatchResult}; +use crate::tokenizing::TokenReader; +use crate::tokenizing::{EOFToken, Token}; +use std::any::TypeId; + +struct AToken; +struct BToken; +struct CToken; + +fn get_reader() -> TokenReader { + let tokens = vec![ + Token::new(AToken), + Token::new(BToken), + Token::new(AToken), + Token::new(CToken), + Token::new(CToken), + Token::new(EOFToken), + ]; + + TokenReader::new(tokens) +} + +#[tokio::test] +async fn it_works() { + let mut reader = get_reader(); + assert!(match_one::(&mut reader).await.unwrap().is_some()); + + assert!(match_many( + &mut reader, + &[TypeId::of::(), TypeId::of::()], + ) + .await + .unwrap() + .is_some()); + + assert_eq!( + match_many_mul( + &mut reader, + &[TypeId::of::(), TypeId::of::()], + ) + .await + .unwrap() + .unwrap(), + 3 + ); + + assert!(match_one::(&mut reader).await.unwrap().is_some()) +} + +#[tokio::test] +async fn test_macro_matching() { + let mut reader = get_reader(); + assert!(match_with_macro(&mut reader).await.unwrap().is_some()); +} + +async fn match_with_macro(reader: &mut TokenReader) -> MatchResult<()> { + do_match!(match_one::(reader)); + do_match!(match_many( + reader, + &[TypeId::of::(), TypeId::of::()] + )); + do_match!(match_many_mul_plus( + reader, + &[TypeId::of::(), TypeId::of::()] + )); + do_match!(match_one::(reader)); + + Ok(Some(())) +} diff --git a/src/tokenizing/token.rs b/src/tokenizing/token.rs index bd59445..ffdd0f8 100644 --- a/src/tokenizing/token.rs +++ b/src/tokenizing/token.rs @@ -39,7 +39,12 @@ impl Token { /// Checks if the inner value is of a given concrete type pub fn is(&self) -> bool { - self.inner.as_ref().type_id() == TypeId::of::() + self.inner_type_id() == TypeId::of::() + } + + /// Returns the TypeID of the inner stored type + pub fn inner_type_id(&self) -> TypeId { + self.inner.as_ref().type_id() } }