Skip to content

Commit c2f11d4

Browse files
committed
Define analyzer traits so phases can plug into the pipeline
1 parent eb2808d commit c2f11d4

File tree

2 files changed

+243
-0
lines changed

2 files changed

+243
-0
lines changed

src/core/semantic_analyzer/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@ use compiler_macros::EnumKindName;
33
pub mod context;
44
pub mod diagnostics;
55
pub mod symbol_table;
6+
pub mod traits;
67
pub mod type_resolver;
78

89
// Re-export main types for convenience
910
pub use context::{AnalysisContext, AnalysisResult};
1011
pub use diagnostics::{DiagnosticCode, FixHint, SemanticDiagnostic};
1112
pub use symbol_table::{Symbol, SymbolTable, SymbolType};
13+
pub use traits::{
14+
AttributeAnalyzer, DeclarationAnalyzer, PhaseAnalyzer, RelationshipAnalyzer,
15+
};
1216

1317
/// Configuration options for semantic analysis.
1418
/// Validation mode configuration
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
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

Comments
 (0)