1#![warn(missing_docs, clippy::all, clippy::pedantic)]
38#![deny(unsafe_code)]
39#![allow(clippy::module_name_repetitions)]
40
41use anyhow::Result;
42use spydecy_hir::unified::UnifiedHIR;
43
44pub trait Pass: Send + Sync {
48 fn name(&self) -> &'static str;
50
51 fn run(&self, hir: UnifiedHIR) -> Result<UnifiedHIR>;
57}
58
59pub struct BoundaryEliminationPass;
66
67impl BoundaryEliminationPass {
68 #[must_use]
70 pub const fn new() -> Self {
71 Self
72 }
73}
74
75impl Default for BoundaryEliminationPass {
76 fn default() -> Self {
77 Self::new()
78 }
79}
80
81impl Pass for BoundaryEliminationPass {
82 fn name(&self) -> &'static str {
83 "BoundaryElimination"
84 }
85
86 fn run(&self, hir: UnifiedHIR) -> Result<UnifiedHIR> {
87 Ok(hir.eliminate_boundary())
89 }
90}
91
92pub struct OptimizationPipeline {
96 passes: Vec<Box<dyn Pass>>,
97}
98
99impl OptimizationPipeline {
100 #[must_use]
102 pub fn new() -> Self {
103 Self { passes: Vec::new() }
104 }
105
106 #[must_use]
108 pub fn standard() -> Self {
109 let mut pipeline = Self::new();
110 pipeline.add_pass(Box::new(BoundaryEliminationPass::new()));
111 pipeline
112 }
113
114 pub fn add_pass(&mut self, pass: Box<dyn Pass>) {
116 self.passes.push(pass);
117 }
118
119 pub fn run(&self, mut hir: UnifiedHIR) -> Result<UnifiedHIR> {
125 for pass in &self.passes {
126 hir = pass.run(hir)?;
127 }
128 Ok(hir)
129 }
130
131 #[must_use]
133 pub fn pass_count(&self) -> usize {
134 self.passes.len()
135 }
136}
137
138impl Default for OptimizationPipeline {
139 fn default() -> Self {
140 Self::new()
141 }
142}
143
144#[cfg(test)]
145#[allow(clippy::expect_used, clippy::panic)]
146mod tests {
147 use super::*;
148 use spydecy_hir::{
149 metadata::Metadata,
150 types::Type,
151 unified::{CrossMapping, UnificationPattern},
152 Language, NodeId,
153 };
154
155 #[test]
156 fn test_boundary_elimination_pass() {
157 let hir = UnifiedHIR::Call {
159 id: NodeId::new(1),
160 target_language: Language::Python,
161 callee: "len".to_owned(),
162 args: vec![],
163 inferred_type: Type::Unknown,
164 source_language: Language::Python,
165 cross_mapping: Some(CrossMapping {
166 python_node: None,
167 c_node: None,
168 pattern: UnificationPattern::LenPattern,
169 boundary_eliminated: false,
170 }),
171 meta: Metadata::new(),
172 };
173
174 let pass = BoundaryEliminationPass::new();
176 let optimized = pass.run(hir).expect("Pass should succeed");
177
178 if let UnifiedHIR::Call { cross_mapping, .. } = optimized {
180 let mapping = cross_mapping.expect("Mapping should exist");
181 assert!(mapping.boundary_eliminated, "Boundary should be eliminated");
182 } else {
183 panic!("Expected UnifiedHIR::Call");
184 }
185 }
186
187 #[test]
188 fn test_pipeline_creation() {
189 let pipeline = OptimizationPipeline::new();
190 assert_eq!(pipeline.pass_count(), 0);
191 }
192
193 #[test]
194 fn test_pipeline_add_pass() {
195 let mut pipeline = OptimizationPipeline::new();
196 pipeline.add_pass(Box::new(BoundaryEliminationPass::new()));
197 assert_eq!(pipeline.pass_count(), 1);
198 }
199
200 #[test]
201 fn test_standard_pipeline() {
202 let pipeline = OptimizationPipeline::standard();
203 assert_eq!(
204 pipeline.pass_count(),
205 1,
206 "Standard pipeline should have 1 pass"
207 );
208 }
209
210 #[test]
211 fn test_pipeline_run() {
212 let hir = UnifiedHIR::Call {
214 id: NodeId::new(1),
215 target_language: Language::Python,
216 callee: "len".to_owned(),
217 args: vec![],
218 inferred_type: Type::Unknown,
219 source_language: Language::Python,
220 cross_mapping: Some(CrossMapping {
221 python_node: None,
222 c_node: None,
223 pattern: UnificationPattern::LenPattern,
224 boundary_eliminated: false,
225 }),
226 meta: Metadata::new(),
227 };
228
229 let pipeline = OptimizationPipeline::standard();
231 let optimized = pipeline.run(hir).expect("Pipeline should succeed");
232
233 if let UnifiedHIR::Call { cross_mapping, .. } = optimized {
235 let mapping = cross_mapping.expect("Mapping should exist");
236 assert!(
237 mapping.boundary_eliminated,
238 "Pipeline should eliminate boundary"
239 );
240 }
241 }
242}