|
| 1 | +//! Core traits for semantic analysis components. |
| 2 | +//! |
| 3 | +//! This module defines the trait-based architecture that makes the semantic |
| 4 | +//! analyzer fully pluggable. Different analyzer implementations can be composed |
| 5 | +//! together to create custom analysis pipelines. |
| 6 | +
|
| 7 | +use crate::core::parser::ast::{FieldAttribute, Schema}; |
| 8 | +use crate::core::semantic_analyzer::{ |
| 9 | + context::{AnalysisContext, PhaseResult}, |
| 10 | + diagnostics::SemanticDiagnostic, |
| 11 | +}; |
| 12 | + |
| 13 | +/// Core trait for analysis phases. |
| 14 | +/// |
| 15 | +/// Each semantic analysis phase implements this trait to provide a standardized |
| 16 | +/// interface for the orchestrator. Phases can declare dependencies and specify |
| 17 | +/// whether they support parallel execution. |
| 18 | +/// |
| 19 | +/// ## Examples |
| 20 | +/// |
| 21 | +/// ```rust,ignore |
| 22 | +/// struct MyAnalyzer; |
| 23 | +/// |
| 24 | +/// impl PhaseAnalyzer for MyAnalyzer { |
| 25 | +/// fn phase_name(&self) -> &'static str { |
| 26 | +/// "Custom Analysis" |
| 27 | +/// } |
| 28 | +/// |
| 29 | +/// fn analyze(&self, schema: &Schema, context: &AnalysisContext) -> PhaseResult { |
| 30 | +/// let mut diagnostics = Vec::new(); |
| 31 | +/// // Perform analysis... |
| 32 | +/// PhaseResult::new(diagnostics) |
| 33 | +/// } |
| 34 | +/// } |
| 35 | +/// ``` |
| 36 | +pub trait PhaseAnalyzer: Send + Sync { |
| 37 | + /// Get the name of this analysis phase for debugging and dependency resolution. |
| 38 | + fn phase_name(&self) -> &'static str; |
| 39 | + |
| 40 | + /// Analyze the schema in this phase. |
| 41 | + /// |
| 42 | + /// The analyzer should examine the schema and context, perform its specific |
| 43 | + /// analysis, and return diagnostics. It may also update the shared state |
| 44 | + /// through the context's Arc<`RwLock`<>> protected fields. |
| 45 | + fn analyze( |
| 46 | + &self, |
| 47 | + schema: &Schema, |
| 48 | + context: &AnalysisContext, |
| 49 | + ) -> PhaseResult; |
| 50 | + |
| 51 | + /// Get the analysis dependencies (phases that must run before this one). |
| 52 | + /// |
| 53 | + /// Dependencies are specified by phase name. The orchestrator will ensure |
| 54 | + /// that all dependencies are completed before running this analyzer. |
| 55 | + fn dependencies(&self) -> &[&'static str] { |
| 56 | + &[] |
| 57 | + } |
| 58 | + |
| 59 | + /// Whether this analyzer can run in parallel with others. |
| 60 | + /// |
| 61 | + /// Analyzers that only read from the context and don't modify shared state |
| 62 | + /// can often run in parallel with other analyzers that have the same |
| 63 | + /// property. |
| 64 | + fn supports_parallel_execution(&self) -> bool { |
| 65 | + false |
| 66 | + } |
| 67 | + |
| 68 | + /// Get the priority of this analyzer within its dependency level. |
| 69 | + /// |
| 70 | + /// When multiple analyzers can run at the same time, those with higher |
| 71 | + /// priority will be scheduled first. Default priority is 0. |
| 72 | + fn priority(&self) -> i32 { |
| 73 | + 0 |
| 74 | + } |
| 75 | +} |
| 76 | + |
| 77 | +/// Trait for analyzing individual declarations. |
| 78 | +/// |
| 79 | +/// This trait allows for fine-grained analysis of specific declaration types |
| 80 | +/// (models, enums, etc.). Analyzers can implement this trait to focus on |
| 81 | +/// particular aspects of declarations. |
| 82 | +pub trait DeclarationAnalyzer<T>: Send + Sync { |
| 83 | + /// Analyze a specific declaration and return any diagnostics. |
| 84 | + fn analyze_declaration( |
| 85 | + &self, |
| 86 | + decl: &T, |
| 87 | + context: &AnalysisContext, |
| 88 | + ) -> Vec<SemanticDiagnostic>; |
| 89 | + |
| 90 | + /// Get the name of this declaration analyzer for debugging. |
| 91 | + fn analyzer_name(&self) -> &'static str; |
| 92 | +} |
| 93 | + |
| 94 | +/// Trait for analyzing relationships between declarations. |
| 95 | +/// |
| 96 | +/// Relationship analyzers examine how different schema elements interact, |
| 97 | +/// such as foreign key relationships, inheritance, or dependencies. |
| 98 | +pub trait RelationshipAnalyzer: Send + Sync { |
| 99 | + /// Analyze relationships within the entire schema. |
| 100 | + fn analyze_relationships( |
| 101 | + &self, |
| 102 | + schema: &Schema, |
| 103 | + context: &AnalysisContext, |
| 104 | + ) -> Vec<SemanticDiagnostic>; |
| 105 | + |
| 106 | + /// Get the name of this relationship analyzer. |
| 107 | + fn analyzer_name(&self) -> &'static str; |
| 108 | +} |
| 109 | + |
| 110 | +/// Trait for analyzing attributes and their arguments. |
| 111 | +/// |
| 112 | +/// Attribute analyzers validate that attributes are used correctly, have |
| 113 | +/// valid arguments, and don't conflict with other attributes. |
| 114 | +pub trait AttributeAnalyzer: Send + Sync { |
| 115 | + /// Analyze a specific attribute in context. |
| 116 | + fn analyze_attribute( |
| 117 | + &self, |
| 118 | + attr: &FieldAttribute, |
| 119 | + context: &AttributeContext, |
| 120 | + ) -> Vec<SemanticDiagnostic>; |
| 121 | + |
| 122 | + /// Get the set of attribute names this analyzer handles. |
| 123 | + fn supported_attributes(&self) -> &[&'static str]; |
| 124 | + |
| 125 | + /// Get the name of this attribute analyzer. |
| 126 | + fn analyzer_name(&self) -> &'static str; |
| 127 | +} |
| 128 | + |
| 129 | +/// Context for attribute analysis. |
| 130 | +/// |
| 131 | +/// Provides additional context about where an attribute appears and what |
| 132 | +/// element it's attached to. |
| 133 | +#[derive(Debug, Clone)] |
| 134 | +pub struct AttributeContext<'a> { |
| 135 | + /// The schema element this attribute is attached to |
| 136 | + pub element_type: AttributeElementType, |
| 137 | + |
| 138 | + /// The name of the parent element (model name, field name, etc.) |
| 139 | + pub element_name: &'a str, |
| 140 | + |
| 141 | + /// Reference to the main analysis context |
| 142 | + pub analysis_context: &'a AnalysisContext, |
| 143 | +} |
| 144 | + |
| 145 | +/// Types of schema elements that can have attributes. |
| 146 | +#[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 147 | +pub enum AttributeElementType { |
| 148 | + Model, |
| 149 | + Field, |
| 150 | + Enum, |
| 151 | + EnumValue, |
| 152 | + Datasource, |
| 153 | + Generator, |
| 154 | +} |
| 155 | + |
| 156 | +/// Trait for custom validation rules. |
| 157 | +/// |
| 158 | +/// This trait allows users to implement custom business logic and validation |
| 159 | +/// rules that are specific to their use case. |
| 160 | +pub trait CustomRule: Send + Sync { |
| 161 | + /// Apply the custom rule to the schema. |
| 162 | + fn apply_rule( |
| 163 | + &self, |
| 164 | + schema: &Schema, |
| 165 | + context: &AnalysisContext, |
| 166 | + ) -> Vec<SemanticDiagnostic>; |
| 167 | + |
| 168 | + /// Get the name of this custom rule. |
| 169 | + fn rule_name(&self) -> &'static str; |
| 170 | + |
| 171 | + /// Get the priority of this rule (higher priority rules run first). |
| 172 | + fn priority(&self) -> i32 { |
| 173 | + 0 |
| 174 | + } |
| 175 | +} |
| 176 | + |
| 177 | +/// Trait for composable analyzer components. |
| 178 | +/// |
| 179 | +/// This trait allows analyzers to be composed together into larger analysis |
| 180 | +/// units while maintaining introspection capabilities for debugging and testing. |
| 181 | +pub trait CompositeAnalyzer { |
| 182 | + /// Get the name of this analyzer component. |
| 183 | + fn component_name(&self) -> &'static str; |
| 184 | + |
| 185 | + /// Get child analyzer components if this is a composite. |
| 186 | + fn child_components(&self) -> Vec<&dyn CompositeAnalyzer> { |
| 187 | + Vec::new() |
| 188 | + } |
| 189 | + |
| 190 | + /// Get a hierarchical description of this analyzer's structure. |
| 191 | + fn structure_description(&self) -> String { |
| 192 | + let mut desc = self.component_name().to_string(); |
| 193 | + let children = self.child_components(); |
| 194 | + if !children.is_empty() { |
| 195 | + desc.push_str(" { "); |
| 196 | + for (i, child) in children.iter().enumerate() { |
| 197 | + if i > 0 { |
| 198 | + desc.push_str(", "); |
| 199 | + } |
| 200 | + desc.push_str(&child.structure_description()); |
| 201 | + } |
| 202 | + desc.push_str(" }"); |
| 203 | + } |
| 204 | + desc |
| 205 | + } |
| 206 | +} |
| 207 | + |
| 208 | +/// Trait for analyzers that can provide progress information. |
| 209 | +/// |
| 210 | +/// This trait enables progress monitoring and timeout detection for long-running |
| 211 | +/// analysis operations. |
| 212 | +pub trait ProgressReporting { |
| 213 | + /// Get the current progress as a percentage (0.0 to 1.0). |
| 214 | + fn progress(&self) -> f32; |
| 215 | + |
| 216 | + /// Get a description of what the analyzer is currently doing. |
| 217 | + fn current_activity(&self) -> Option<&str>; |
| 218 | + |
| 219 | + /// Check if the analyzer is still making progress. |
| 220 | + fn is_making_progress(&self) -> bool; |
| 221 | + |
| 222 | + /// Get the time when this analyzer last made progress. |
| 223 | + fn last_progress_time(&self) -> std::time::Instant; |
| 224 | +} |
| 225 | + |
| 226 | +/// Trait for analyzers that support cancellation. |
| 227 | +/// |
| 228 | +/// Analyzers implementing this trait can be interrupted and stopped gracefully |
| 229 | +/// when timeouts occur or when the user requests cancellation. |
| 230 | +pub trait Cancellable { |
| 231 | + /// Request that the analyzer cancel its current operation. |
| 232 | + fn request_cancellation(&mut self); |
| 233 | + |
| 234 | + /// Check if cancellation has been requested. |
| 235 | + fn is_cancelled(&self) -> bool; |
| 236 | + |
| 237 | + /// Reset the cancellation state. |
| 238 | + fn reset_cancellation(&mut self); |
| 239 | +} |
0 commit comments