baobao_codegen/pipeline/
context.rs1use baobao_ir::AppIR;
4use baobao_manifest::Manifest;
5
6use super::diagnostic::{Diagnostic, Severity};
7use crate::schema::ComputedData;
8
9#[derive(Debug)]
14pub struct CompilationContext {
15 pub manifest: Manifest,
17 pub ir: Option<AppIR>,
19 pub computed: Option<ComputedData>,
21 pub diagnostics: Vec<Diagnostic>,
23}
24
25impl CompilationContext {
26 pub fn new(manifest: Manifest) -> Self {
28 Self {
29 manifest,
30 ir: None,
31 computed: None,
32 diagnostics: Vec::new(),
33 }
34 }
35
36 pub fn has_errors(&self) -> bool {
38 self.diagnostics.iter().any(|d| d.severity.is_error())
39 }
40
41 pub fn has_warnings(&self) -> bool {
43 self.diagnostics.iter().any(|d| d.severity.is_warning())
44 }
45
46 pub fn error_count(&self) -> usize {
48 self.diagnostics
49 .iter()
50 .filter(|d| d.severity.is_error())
51 .count()
52 }
53
54 pub fn warning_count(&self) -> usize {
56 self.diagnostics
57 .iter()
58 .filter(|d| d.severity.is_warning())
59 .count()
60 }
61
62 pub fn add_error(&mut self, phase: &str, message: impl Into<String>) {
64 self.diagnostics.push(Diagnostic::error(phase, message));
65 }
66
67 pub fn add_warning(&mut self, phase: &str, message: impl Into<String>) {
69 self.diagnostics.push(Diagnostic::warning(phase, message));
70 }
71
72 pub fn add_info(&mut self, phase: &str, message: impl Into<String>) {
74 self.diagnostics.push(Diagnostic::info(phase, message));
75 }
76
77 pub fn add_diagnostic(&mut self, diagnostic: Diagnostic) {
79 self.diagnostics.push(diagnostic);
80 }
81
82 pub fn errors(&self) -> impl Iterator<Item = &Diagnostic> {
84 self.diagnostics
85 .iter()
86 .filter(|d| matches!(d.severity, Severity::Error))
87 }
88
89 pub fn warnings(&self) -> impl Iterator<Item = &Diagnostic> {
91 self.diagnostics
92 .iter()
93 .filter(|d| matches!(d.severity, Severity::Warning))
94 }
95
96 pub fn take_ir(&mut self) -> AppIR {
102 self.ir.take().expect("IR not set - did LowerPhase run?")
103 }
104
105 pub fn take_computed(&mut self) -> ComputedData {
111 self.computed
112 .take()
113 .expect("ComputedData not set - did AnalyzePhase run?")
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 fn parse_manifest(content: &str) -> Manifest {
122 toml::from_str(content).expect("Failed to parse test manifest")
123 }
124
125 fn make_test_manifest() -> Manifest {
126 parse_manifest(
127 r#"
128 [cli]
129 name = "test"
130 language = "rust"
131 "#,
132 )
133 }
134
135 #[test]
136 fn test_context_creation() {
137 let manifest = make_test_manifest();
138 let ctx = CompilationContext::new(manifest);
139
140 assert!(ctx.ir.is_none());
141 assert!(ctx.computed.is_none());
142 assert!(ctx.diagnostics.is_empty());
143 }
144
145 #[test]
146 fn test_context_diagnostics() {
147 let manifest = make_test_manifest();
148 let mut ctx = CompilationContext::new(manifest);
149
150 ctx.add_error("test", "test error");
151 ctx.add_warning("test", "test warning");
152
153 assert!(ctx.has_errors());
154 assert!(ctx.has_warnings());
155 assert_eq!(ctx.error_count(), 1);
156 assert_eq!(ctx.warning_count(), 1);
157 }
158
159 #[test]
160 fn test_context_no_errors() {
161 let manifest = make_test_manifest();
162 let mut ctx = CompilationContext::new(manifest);
163
164 ctx.add_warning("test", "just a warning");
165 ctx.add_info("test", "just info");
166
167 assert!(!ctx.has_errors());
168 assert!(ctx.has_warnings());
169 }
170}