use crate::host::MacroRegistry;
use crate::ts_syn::TsStream;
use crate::ts_syn::abi::{Diagnostic, DiagnosticLevel, MacroContextIR, MacroResult};
pub struct MacroDispatcher {
registry: MacroRegistry,
}
impl MacroDispatcher {
pub fn new(registry: MacroRegistry) -> Self {
Self { registry }
}
pub fn dispatch(&self, ctx: MacroContextIR) -> MacroResult {
match self
.registry
.lookup_with_fallback(&ctx.module_path, &ctx.macro_name)
{
Ok(macro_impl) => {
let impl_abi = macro_impl.abi_version();
if impl_abi != ctx.abi_version {
return MacroResult {
diagnostics: vec![Diagnostic {
level: DiagnosticLevel::Error,
message: format!(
"ABI version mismatch: expected {}, got {}",
ctx.abi_version, impl_abi
),
span: Some(ctx.decorator_span),
notes: vec![],
help: Some(
"The macro may need to be rebuilt with the current ABI version"
.to_string(),
),
}],
..Default::default()
};
}
let input =
match TsStream::with_context(&ctx.target_source, &ctx.file_name, ctx.clone()) {
Ok(stream) => stream,
Err(err) => {
return MacroResult {
diagnostics: vec![Diagnostic {
level: DiagnosticLevel::Error,
message: format!("Failed to create TsStream: {:?}", err),
span: Some(ctx.decorator_span),
notes: vec![],
help: None,
}],
..Default::default()
};
}
};
match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
macro_impl.run(input)
})) {
Ok(result) => result,
Err(panic_err) => {
let panic_msg = if let Some(s) = panic_err.downcast_ref::<String>() {
s.clone()
} else if let Some(s) = panic_err.downcast_ref::<&str>() {
s.to_string()
} else {
"Unknown panic in macro execution".to_string()
};
MacroResult {
diagnostics: vec![Diagnostic {
level: DiagnosticLevel::Error,
message: format!("Macro execution panicked: {}", panic_msg),
span: Some(ctx.decorator_span),
notes: vec![],
help: None,
}],
..Default::default()
}
}
}
}
Err(_err) => {
MacroResult {
diagnostics: vec![Diagnostic {
level: DiagnosticLevel::Error,
message: format!(
"Macro '{}' is not a Macroforge built-in macro. Ensure you are using the 'import macro' syntax import statement.",
ctx.macro_name
),
span: Some(ctx.decorator_span),
notes: vec![],
help: None,
}],
..Default::default()
}
}
}
}
pub fn registry(&self) -> &MacroRegistry {
&self.registry
}
}