use super::{MacroEnvironment, Pattern, Template, HygieneContext, PatternBindings};
use crate::ast::Expr;
use crate::diagnostics::{Error, Result, Span, Spanned};
#[derive(Debug, Clone)]
pub struct ExpansionConfig {
pub max_depth: usize,
pub hygiene_enabled: bool,
pub collect_stats: bool,
}
impl Default for ExpansionConfig {
fn default() -> Self {
Self {
max_depth: 100,
hygiene_enabled: true,
collect_stats: false,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct ExpansionStats {
pub expansions: usize,
pub max_depth_reached: usize,
pub hygiene_renamings: usize,
}
pub struct ConfigurableExpander {
pub macro_env: MacroEnvironment,
pub expansion_depth: usize,
pub max_expansion_depth: usize,
pub hygiene_context: HygieneContext,
pub config: ExpansionConfig,
pub stats: ExpansionStats,
}
impl Default for ConfigurableExpander {
fn default() -> Self {
Self::new()
}
}
impl ConfigurableExpander {
pub fn new() -> Self {
Self {
macro_env: MacroEnvironment::new(),
expansion_depth: 0,
max_expansion_depth: 100,
hygiene_context: HygieneContext::new(),
config: ExpansionConfig::default(),
stats: ExpansionStats::default(),
}
}
pub fn with_config(config: ExpansionConfig) -> Self {
Self {
macro_env: MacroEnvironment::new(),
expansion_depth: 0,
max_expansion_depth: config.max_depth,
hygiene_context: HygieneContext::new(),
config,
stats: ExpansionStats::default(),
}
}
pub fn expand_macro(
&mut self,
transformer: &SyntaxTransformer,
args: &[Spanned<Expr>],
span: Span,
) -> Result<Spanned<Expr>> {
for rule in &transformer.rules {
let mut bindings = crate::macro_system::PatternBindings::new();
if self.try_match_simple_pattern(&rule.pattern, args, &mut bindings).is_ok() {
let expanded = rule.template.expand(&bindings, span)?;
if self.config.hygiene_enabled {
use crate::eval::Environment;
let env = Environment::new(None, 0);
let renamed_expr = self.hygiene_context.rename_identifiers(
expanded.clone(),
&env
)?;
if self.config.collect_stats {
self.stats.hygiene_renamings += 1;
}
return Ok(renamed_expr);
}
return Ok(expanded);
}
}
Err(Box::new(Error::macro_error(
"No matching pattern for macro".to_string(),
span,
)))
}
pub fn reset(&mut self) {
self.expansion_depth = 0;
self.stats = ExpansionStats::default();
}
pub fn stats(&self) -> &ExpansionStats {
&self.stats
}
fn try_match_simple_pattern(
&self,
_pattern: &Pattern,
_args: &[Spanned<Expr>],
_bindings: &mut PatternBindings,
) -> Result<()> {
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct SyntaxTransformer {
pub rules: Vec<SyntaxRule>,
pub name: Option<String>,
}
#[derive(Debug, Clone)]
pub struct SyntaxRule {
pub pattern: Pattern,
pub template: Template,
}
impl SyntaxTransformer {
pub fn new(rules: Vec<SyntaxRule>) -> Self {
Self {
rules,
name: None,
}
}
pub fn with_name(rules: Vec<SyntaxRule>, name: String) -> Self {
Self {
rules,
name: Some(name),
}
}
}
impl SyntaxRule {
pub fn new(pattern: Pattern, template: Template) -> Self {
Self { pattern, template }
}
}