use crate::compile::pattern::sub::SubPatternCodeGen;
use crate::traits::Pattern;
use proc_macro2::TokenStream;
use quote::quote_spanned;
pub trait PatternCodeGen {
fn generate<S: SubPatternCodeGen>(pattern: &dyn Pattern) -> TokenStream;
}
pub struct PatternCompiler;
impl PatternCodeGen for PatternCompiler {
fn generate<S: SubPatternCodeGen>(pattern: &dyn Pattern) -> TokenStream {
let sub_patterns = pattern
.sub_patterns()
.into_iter()
.map(|sp| S::generate(&*sp, false))
.collect::<Vec<TokenStream>>();
if sub_patterns.len() == 1 {
let sub_pattern = sub_patterns[0].clone();
return quote_spanned!( pattern.span() => #sub_pattern );
}
quote_spanned!( pattern.span() => (#(#sub_patterns),*) )
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::compile::pattern::sub::SubPatternCodeGen;
use crate::parse::sub_pattern::SubPatternDefinition;
use crate::traits::SubPattern;
use proc_macro_utils::assert_tokens;
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::Ident;
struct MockSubPattern;
impl SubPattern for MockSubPattern {
fn get(&self) -> SubPatternDefinition {
unimplemented!()
}
fn get_identifier(&self) -> &Ident {
unimplemented!()
}
}
struct MockPattern {
sub_patterns: Vec<MockSubPattern>,
}
impl MockPattern {
fn new(pattern_size: usize) -> Self {
Self {
sub_patterns: (0..pattern_size).map(|_| MockSubPattern).collect(),
}
}
}
impl Pattern for MockPattern {
fn sub_patterns(&self) -> Vec<&dyn SubPattern> {
self.sub_patterns
.iter()
.map(|sp| sp as &dyn SubPattern)
.collect()
}
fn len(&self) -> usize {
unimplemented!()
}
fn span(&self) -> Span {
Span::call_site()
}
}
struct MockSubPatternCodeGen;
impl SubPatternCodeGen for MockSubPatternCodeGen {
fn generate(_mock_pattern: &dyn SubPattern, _anonymous: bool) -> TokenStream {
quote!(mock_sp_ident)
}
}
#[test]
fn test_single_sub_pattern() {
let pattern = MockPattern::new(1);
let result = PatternCompiler::generate::<MockSubPatternCodeGen>(&pattern);
assert_tokens!(result, { mock_sp_ident });
}
#[test]
fn test_multiple_sub_patterns() {
let pattern = MockPattern::new(3);
let result = PatternCompiler::generate::<MockSubPatternCodeGen>(&pattern);
assert_tokens!(result, { (mock_sp_ident, mock_sp_ident, mock_sp_ident) });
}
}