use crate::utils::{GcIntegration, GcIntegrationConfig};
use crate::utils::gc::{ObjectId, gc_alloc};
use crate::macro_system::{MacroExpander, MacroTransformer, HygieneContext, next_hygiene_id};
use crate::eval::{Value, ThreadSafeEnvironment};
use crate::eval::gc_coordinator::GcCoordinator;
use crate::ast::{Expr};
use crate::diagnostics::{Result, Error, Span, Spanned};
use std::sync::{Arc, RwLock, Mutex};
use std::collections::HashMap;
use std::time::Instant;
#[derive(Debug)]
pub struct GcMacroCoordinator {
expander: Arc<Mutex<MacroExpander>>,
gc_integration: Arc<GcIntegration>,
expansion_contexts: RwLock<HashMap<ExpansionId, ExpansionContext>>,
transformer_registry: RwLock<HashMap<String, TransformerEntry>>,
config: GcMacroConfig,
next_expansion_id: std::sync::atomic::AtomicU64,
}
#[derive(Debug, Clone)]
pub struct GcMacroConfig {
pub track_expansions: bool,
pub preserve_intermediates: bool,
pub gc_during_expansion: bool,
pub max_expansion_depth: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ExpansionId(u64);
#[derive(Debug)]
pub struct ExpansionContext {
pub id: ExpansionId,
pub macro_name: String,
pub environment: Arc<ThreadSafeEnvironment>,
pub hygiene_context: HygieneContext,
pub input_expr: Spanned<Expr>,
pub intermediates: Vec<Spanned<Expr>>,
pub start_time: Instant,
pub depth: usize,
pub gc_object_id: Option<ObjectId>,
}
#[derive(Debug, Clone)]
pub struct TransformerEntry {
pub name: String,
pub transformer: Value,
pub environment: Arc<ThreadSafeEnvironment>,
pub registered_at: Instant,
pub gc_object_id: Option<ObjectId>,
}
#[derive(Debug, Clone)]
pub struct GcMacroExpansionResult {
pub result: Spanned<Expr>,
pub stats: ExpansionStats,
pub gc_triggered: bool,
}
#[derive(Debug, Clone)]
pub struct ExpansionStats {
pub expansion_time: std::time::Duration,
pub expansion_steps: usize,
pub max_depth: usize,
pub intermediates_created: usize,
pub estimated_memory_usage: usize,
}
impl GcMacroCoordinator {
pub fn new(
expander: MacroExpander,
gc_integration: Arc<GcIntegration>,
config: GcMacroConfig,
) -> Self {
Self {
expander: Arc::new(Mutex::new(expander)),
gc_integration,
expansion_contexts: RwLock::new(HashMap::new()),
transformer_registry: RwLock::new(HashMap::new()),
config,
next_expansion_id: std::sync::atomic::AtomicU64::new(1),
}
}
pub fn with_default_config(
expander: MacroExpander,
gc_integration: Arc<GcIntegration>,
) -> Self {
Self::new(expander, gc_integration, GcMacroConfig::default())
}
pub fn register_transformer(
&self,
name: String,
transformer: Value,
environment: Arc<ThreadSafeEnvironment>,
) -> Result<()> {
let entry = TransformerEntry {
name: name.clone(),
transformer: transformer.clone(),
environment,
registered_at: Instant::now(),
gc_object_id: None, };
if let Ok(mut registry) = self.transformer_registry.write() {
registry.insert(name.clone(), entry);
if self.config.track_expansions {
let object_id = ObjectId::new(next_hygiene_id());
self.gc_integration.register_macro_root(object_id);
if let Some(entry) = registry.get_mut(&name) {
entry.gc_object_id = Some(object_id);
}
}
}
Ok(())
}
pub fn expand_with_gc_tracking(
&self,
expr: Spanned<Expr>,
env: Arc<ThreadSafeEnvironment>,
) -> Result<GcMacroExpansionResult> {
let start_time = Instant::now();
let expansion_id = ExpansionId(
self.next_expansion_id
.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
);
let context = ExpansionContext {
id: expansion_id,
macro_name: self.extract_macro_name(&expr),
environment: env.clone(),
hygiene_context: HygieneContext::new(),
input_expr: expr.clone(),
intermediates: Vec::new(),
start_time,
depth: 0,
gc_object_id: None,
};
if self.config.track_expansions {
let object_id = ObjectId::new(expansion_id.0);
self.gc_integration.register_macro_root(object_id);
if let Ok(mut contexts) = self.expansion_contexts.write() {
let mut context = context;
context.gc_object_id = Some(object_id);
contexts.insert(expansion_id, context);
}
}
let result = self.perform_tracked_expansion(expansion_id, expr, env)?;
self.cleanup_expansion_context(expansion_id);
let expansion_time = start_time.elapsed();
Ok(GcMacroExpansionResult {
result: result.result,
stats: ExpansionStats {
expansion_time,
expansion_steps: result.steps,
max_depth: result.max_depth,
intermediates_created: result.intermediates_count,
estimated_memory_usage: result.estimated_memory,
},
gc_triggered: result.gc_triggered,
})
}
fn perform_tracked_expansion(
&self,
expansion_id: ExpansionId,
expr: Spanned<Expr>,
env: Arc<ThreadSafeEnvironment>,
) -> Result<TrackedExpansionResult> {
let mut steps = 0;
let mut max_depth = 0;
let mut intermediates_count = 0;
let mut estimated_memory = 0;
let mut gc_triggered = false;
if let Ok(mut expander) = self.expander.lock() {
let result = expander.expand(&expr)?;
steps = 1; estimated_memory = Self::estimate_expression_memory(&result);
if self.config.preserve_intermediates {
self.record_intermediate_result(expansion_id, result.clone());
intermediates_count = 1;
}
if self.config.gc_during_expansion && self.should_trigger_gc_during_expansion() {
self.trigger_expansion_gc();
gc_triggered = true;
}
Ok(TrackedExpansionResult {
result,
steps,
max_depth,
intermediates_count,
estimated_memory,
gc_triggered,
})
} else {
Err(Box::new(Error::runtime_error(
"Failed to acquire macro expander lock".to_string(),
None,
)))
}
}
fn record_intermediate_result(&self, expansion_id: ExpansionId, result: Spanned<Expr>) {
if let Ok(mut contexts) = self.expansion_contexts.write() {
if let Some(context) = contexts.get_mut(&expansion_id) {
context.intermediates.push(result);
}
}
}
fn should_trigger_gc_during_expansion(&self) -> bool {
if !self.config.gc_during_expansion {
return false;
}
if let Ok(contexts) = self.expansion_contexts.read() {
contexts.len() > 10 } else {
false
}
}
fn trigger_expansion_gc(&self) {
let expansion_roots = self.collect_expansion_roots();
for root_id in expansion_roots {
self.gc_integration.register_macro_root(root_id);
}
crate::utils::gc::gc_collect();
}
fn collect_expansion_roots(&self) -> Vec<ObjectId> {
let mut roots = Vec::new();
if let Ok(contexts) = self.expansion_contexts.read() {
for context in contexts.values() {
if let Some(object_id) = context.gc_object_id {
roots.push(object_id);
}
}
}
if let Ok(registry) = self.transformer_registry.read() {
for entry in registry.values() {
if let Some(object_id) = entry.gc_object_id {
roots.push(object_id);
}
}
}
roots
}
fn cleanup_expansion_context(&self, expansion_id: ExpansionId) {
if let Ok(mut contexts) = self.expansion_contexts.write() {
if let Some(context) = contexts.remove(&expansion_id) {
if let Some(object_id) = context.gc_object_id {
self.gc_integration.unregister_continuation_root(object_id);
}
}
}
}
fn extract_macro_name(&self, expr: &Spanned<Expr>) -> String {
match &expr.inner {
Expr::Application { operator, .. } => {
match &operator.inner {
Expr::Identifier(name) => name.clone(),
Expr::Symbol(name) => name.clone(),
_ => "<complex-macro>".to_string(),
}
}
Expr::Identifier(name) => name.clone(),
Expr::Symbol(name) => name.clone(),
_ => "<unknown-macro>".to_string(),
}
}
fn estimate_expression_memory(expr: &Spanned<Expr>) -> usize {
match &expr.inner {
Expr::Literal(_) => 32,
Expr::Identifier(_) | Expr::Symbol(_) => 24,
Expr::Application { operator, operands } => {
let operator_size = Self::estimate_expression_memory(operator);
let operands_size: usize = operands
.iter()
.map(Self::estimate_expression_memory)
.sum();
48 + operator_size + operands_size
}
Expr::Lambda { body, .. } => {
let body_size: usize = body
.iter()
.map(Self::estimate_expression_memory)
.sum();
128 + body_size }
Expr::Let { bindings, body } => {
let bindings_size = bindings.len() * 64; let body_size: usize = body
.iter()
.map(Self::estimate_expression_memory)
.sum();
96 + bindings_size + body_size
}
_ => 64, }
}
pub fn get_expansion_statistics(&self) -> MacroExpansionStatistics {
let active_expansions = if let Ok(contexts) = self.expansion_contexts.read() {
contexts.len()
} else {
0
};
let registered_transformers = if let Ok(registry) = self.transformer_registry.read() {
registry.len()
} else {
0
};
MacroExpansionStatistics {
active_expansions,
registered_transformers,
gc_roots_tracked: self.collect_expansion_roots().len(),
}
}
pub fn config(&self) -> &GcMacroConfig {
&self.config
}
}
#[derive(Debug)]
struct TrackedExpansionResult {
result: Spanned<Expr>,
steps: usize,
max_depth: usize,
intermediates_count: usize,
estimated_memory: usize,
gc_triggered: bool,
}
#[derive(Debug, Clone)]
pub struct MacroExpansionStatistics {
pub active_expansions: usize,
pub registered_transformers: usize,
pub gc_roots_tracked: usize,
}
impl Default for GcMacroConfig {
fn default() -> Self {
Self {
track_expansions: true,
preserve_intermediates: false, gc_during_expansion: true,
max_expansion_depth: 1000,
}
}
}
impl ExpansionId {
pub fn raw(&self) -> u64 {
self.0
}
}
pub trait MacroExpanderGcExt {
fn expand_with_gc(&mut self, expr: &Spanned<Expr>, env: &crate::eval::Environment) -> Result<Spanned<Expr>>;
fn register_syntax_with_gc(&mut self, name: String, transformer: Value, env: Arc<ThreadSafeEnvironment>) -> Result<()>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::macro_system::MacroExpander;
use crate::utils::GcIntegration;
use crate::eval::value::{ThreadSafeEnvironment, Value};
use crate::ast::{Expr, Literal};
use crate::diagnostics::Span;
#[test]
fn test_gc_macro_coordinator_creation() {
let expander = MacroExpander::new();
let gc_integration = Arc::new(GcIntegration::with_default_config());
let coordinator = GcMacroCoordinator::with_default_config(expander, gc_integration);
let stats = coordinator.get_expansion_statistics();
assert_eq!(stats.active_expansions, 0);
assert_eq!(stats.registered_transformers, 0);
}
#[test]
fn test_transformer_registration() {
let expander = MacroExpander::new();
let gc_integration = Arc::new(GcIntegration::with_default_config());
let coordinator = GcMacroCoordinator::with_default_config(expander, gc_integration);
let env = Arc::new(ThreadSafeEnvironment::new(None, 0));
let transformer = Value::integer(42);
let result = coordinator.register_transformer(
"test-macro".to_string(),
transformer,
env,
);
assert!(result.is_ok());
let stats = coordinator.get_expansion_statistics();
assert_eq!(stats.registered_transformers, 1);
}
#[test]
fn test_memory_estimation() {
let expander = MacroExpander::new();
let gc_integration = Arc::new(GcIntegration::with_default_config());
let coordinator = GcMacroCoordinator::with_default_config(expander, gc_integration);
let simple_expr = Spanned::new(
Expr::Literal(Literal::Number(42.0)),
Span::new(0, 2),
);
let size = GcCoordinator::estimate_expression_memory(&simple_expr);
assert!(size > 0);
assert!(size < 100); }
}