#![warn(missing_docs, clippy::all, clippy::pedantic)]
#![deny(unsafe_code)]
#![allow(clippy::module_name_repetitions)]
use anyhow::Result;
use spydecy_hir::unified::UnifiedHIR;
pub trait Pass: Send + Sync {
fn name(&self) -> &'static str;
fn run(&self, hir: UnifiedHIR) -> Result<UnifiedHIR>;
}
pub struct BoundaryEliminationPass;
impl BoundaryEliminationPass {
#[must_use]
pub const fn new() -> Self {
Self
}
}
impl Default for BoundaryEliminationPass {
fn default() -> Self {
Self::new()
}
}
impl Pass for BoundaryEliminationPass {
fn name(&self) -> &'static str {
"BoundaryElimination"
}
fn run(&self, hir: UnifiedHIR) -> Result<UnifiedHIR> {
Ok(hir.eliminate_boundary())
}
}
pub struct OptimizationPipeline {
passes: Vec<Box<dyn Pass>>,
}
impl OptimizationPipeline {
#[must_use]
pub fn new() -> Self {
Self { passes: Vec::new() }
}
#[must_use]
pub fn standard() -> Self {
let mut pipeline = Self::new();
pipeline.add_pass(Box::new(BoundaryEliminationPass::new()));
pipeline
}
pub fn add_pass(&mut self, pass: Box<dyn Pass>) {
self.passes.push(pass);
}
pub fn run(&self, mut hir: UnifiedHIR) -> Result<UnifiedHIR> {
for pass in &self.passes {
hir = pass.run(hir)?;
}
Ok(hir)
}
#[must_use]
pub fn pass_count(&self) -> usize {
self.passes.len()
}
}
impl Default for OptimizationPipeline {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::panic)]
mod tests {
use super::*;
use spydecy_hir::{
metadata::Metadata,
types::Type,
unified::{CrossMapping, UnificationPattern},
Language, NodeId,
};
#[test]
fn test_boundary_elimination_pass() {
let hir = UnifiedHIR::Call {
id: NodeId::new(1),
target_language: Language::Python,
callee: "len".to_owned(),
args: vec![],
inferred_type: Type::Unknown,
source_language: Language::Python,
cross_mapping: Some(CrossMapping {
python_node: None,
c_node: None,
pattern: UnificationPattern::LenPattern,
boundary_eliminated: false,
}),
meta: Metadata::new(),
};
let pass = BoundaryEliminationPass::new();
let optimized = pass.run(hir).expect("Pass should succeed");
if let UnifiedHIR::Call { cross_mapping, .. } = optimized {
let mapping = cross_mapping.expect("Mapping should exist");
assert!(mapping.boundary_eliminated, "Boundary should be eliminated");
} else {
panic!("Expected UnifiedHIR::Call");
}
}
#[test]
fn test_pipeline_creation() {
let pipeline = OptimizationPipeline::new();
assert_eq!(pipeline.pass_count(), 0);
}
#[test]
fn test_pipeline_add_pass() {
let mut pipeline = OptimizationPipeline::new();
pipeline.add_pass(Box::new(BoundaryEliminationPass::new()));
assert_eq!(pipeline.pass_count(), 1);
}
#[test]
fn test_standard_pipeline() {
let pipeline = OptimizationPipeline::standard();
assert_eq!(
pipeline.pass_count(),
1,
"Standard pipeline should have 1 pass"
);
}
#[test]
fn test_pipeline_run() {
let hir = UnifiedHIR::Call {
id: NodeId::new(1),
target_language: Language::Python,
callee: "len".to_owned(),
args: vec![],
inferred_type: Type::Unknown,
source_language: Language::Python,
cross_mapping: Some(CrossMapping {
python_node: None,
c_node: None,
pattern: UnificationPattern::LenPattern,
boundary_eliminated: false,
}),
meta: Metadata::new(),
};
let pipeline = OptimizationPipeline::standard();
let optimized = pipeline.run(hir).expect("Pipeline should succeed");
if let UnifiedHIR::Call { cross_mapping, .. } = optimized {
let mapping = cross_mapping.expect("Mapping should exist");
assert!(
mapping.boundary_eliminated,
"Pipeline should eliminate boundary"
);
}
}
}