#![warn(missing_docs)]
pub use nargo_ir::*;
use nargo_types::{Result, Span};
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use std::{collections::VecDeque, path::Path};
pub mod plugin;
pub use plugin::*;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Transformation {
pub name: String,
pub description: String,
pub timestamp: u64,
pub affected_span: Option<Span>,
pub ir_before: Option<String>,
pub ir_after: Option<String>,
}
pub struct Transformer {
logs: VecDeque<Transformation>,
pub enable_snapshots: bool,
plugin_manager: PluginManager,
}
impl Default for Transformer {
fn default() -> Self {
Self::new()
}
}
impl Clone for Transformer {
fn clone(&self) -> Self {
Self {
logs: self.logs.clone(),
enable_snapshots: self.enable_snapshots,
plugin_manager: PluginManager::new(), }
}
}
impl Transformer {
pub fn new() -> Self {
Self { logs: VecDeque::new(), enable_snapshots: false, plugin_manager: PluginManager::new() }
}
pub fn log(&mut self, name: &str, description: &str, span: Option<Span>, ir_before: Option<String>, ir_after: Option<String>) {
let timestamp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap_or_default().as_secs();
self.logs.push_back(Transformation { name: name.into(), description: description.into(), timestamp, affected_span: span, ir_before, ir_after });
}
pub fn get_logs(&self) -> Vec<Transformation> {
self.logs.iter().cloned().collect()
}
pub fn clear_logs(&mut self) {
self.logs.clear();
}
pub fn export_to_json(&self) -> Result<String> {
serde_json::to_string_pretty(&self.get_logs()).map_err(|e| nargo_types::Error::external_error("Transformer".to_string(), format!("Failed to export logs: {}", e), Span::unknown()))
}
pub fn load_plugin<P: Plugin + 'static>(&mut self, plugin: P, config: PluginConfig) -> Result<()> {
self.plugin_manager.load_plugin(plugin, config)
}
pub fn load_plugins_from_directory(&mut self, directory: &Path) -> Result<()> {
self.plugin_manager.load_plugins_from_directory(directory)
}
pub fn run_plugins(&mut self, ir: &mut IRModule, lifecycle: PluginLifecycle) -> Result<()> {
self.plugin_manager.run_plugins(ir, lifecycle)
}
pub fn cleanup_plugins(&mut self) -> Result<()> {
self.plugin_manager.cleanup_plugins()
}
pub fn get_plugins_info(&self) -> Vec<(String, PluginConfig)> {
self.plugin_manager.get_plugins_info()
}
pub fn set_plugin_enabled(&mut self, plugin_name: &str, enabled: bool) -> Result<()> {
self.plugin_manager.set_plugin_enabled(plugin_name, enabled)
}
pub fn apply<T: TransformPass>(&mut self, ir: &mut IRModule, pass: &mut T) -> Result<()> {
self.run_plugins(ir, PluginLifecycle::PreTransform)?;
let name = pass.name();
let description = pass.description();
let ir_before = if self.enable_snapshots { serde_json::to_string(ir).ok() } else { None };
pass.transform(ir)?;
self.run_plugins(ir, PluginLifecycle::Transform)?;
let ir_after = if self.enable_snapshots { serde_json::to_string(ir).ok() } else { None };
self.log(&name, &description, None, ir_before, ir_after);
self.run_plugins(ir, PluginLifecycle::PostTransform)?;
Ok(())
}
pub fn apply_parallel<T: TransformPass + Sync>(&mut self, ir: &mut IRModule, passes: &mut [&mut T]) -> Result<()> {
self.run_plugins(ir, PluginLifecycle::PreTransform)?;
for pass in passes {
pass.transform(ir)?;
}
self.run_plugins(ir, PluginLifecycle::Transform)?;
self.run_plugins(ir, PluginLifecycle::PostTransform)?;
Ok(())
}
pub fn with_span<T, F>(_span: Span, f: F) -> T
where
F: FnOnce() -> T,
{
f()
}
}
pub trait TransformPass {
fn name(&self) -> String;
fn description(&self) -> String;
fn transform(&mut self, ir: &mut IRModule) -> Result<()>;
}
pub mod passes;
pub use passes::*;