Skip to main content

ocelot_base/
compilation_context.rs

1use crate::diagnostic_level::DiagnosticLevel;
2use crate::source_diagnostic::SourceDiagnostic;
3use crate::source_diagnostics::SourceDiagnostics;
4
5/// Compilation state that accumulates source diagnostics.
6#[derive(Debug, Clone, PartialEq, Eq, Default)]
7pub struct CompilationContext {
8    /// Diagnostics produced during compilation.
9    pub source_diagnostics: SourceDiagnostics,
10}
11
12impl CompilationContext {
13    /// Creates a compilation context from the provided source diagnostics.
14    pub fn new(source_diagnostics: SourceDiagnostics) -> Self {
15        Self { source_diagnostics }
16    }
17
18    /// Appends one diagnostic to this compilation context.
19    pub fn add_diagnostic(&mut self, diagnostic: SourceDiagnostic) {
20        self.source_diagnostics.diagnostics.push(diagnostic);
21    }
22
23    /// Appends multiple diagnostics to this compilation context.
24    pub fn add_diagnostics(&mut self, diagnostics: impl IntoIterator<Item = SourceDiagnostic>) {
25        self.source_diagnostics.diagnostics.extend(diagnostics);
26    }
27
28    /// Returns true when any tracked diagnostic has error severity.
29    pub fn has_errors(&self) -> bool {
30        self.source_diagnostics
31            .diagnostics
32            .iter()
33            .any(|diagnostic| diagnostic.level == DiagnosticLevel::Error)
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::CompilationContext;
40    use crate::diagnostic_level::DiagnosticLevel;
41    use crate::source_diagnostic::SourceDiagnostic;
42    use crate::source_diagnostics::SourceDiagnostics;
43
44    #[test]
45    fn compilation_context_reports_errors_when_present() {
46        let context = CompilationContext::new(
47            SourceDiagnostics::new()
48                .with_diagnostic(SourceDiagnostic::new(
49                    DiagnosticLevel::Warning,
50                    "examples/test.ocelot",
51                    "unused value",
52                ))
53                .with_diagnostic(SourceDiagnostic::new(
54                    DiagnosticLevel::Error,
55                    "examples/test.ocelot",
56                    "type mismatch",
57                )),
58        );
59
60        assert!(context.has_errors());
61    }
62
63    #[test]
64    fn compilation_context_reports_no_errors_when_only_warnings_are_present() {
65        let context = CompilationContext::new(SourceDiagnostics::new().with_diagnostic(
66            SourceDiagnostic::new(
67                DiagnosticLevel::Warning,
68                "examples/test.ocelot",
69                "unused value",
70            ),
71        ));
72
73        assert!(!context.has_errors());
74    }
75
76    #[test]
77    fn compilation_context_can_add_one_diagnostic() {
78        let mut context = CompilationContext::default();
79
80        context.add_diagnostic(SourceDiagnostic::new(
81            DiagnosticLevel::Warning,
82            "examples/test.ocelot",
83            "unused value",
84        ));
85
86        assert_eq!(context.source_diagnostics.diagnostics.len(), 1);
87        assert_eq!(
88            context.source_diagnostics.diagnostics[0].message,
89            "unused value"
90        );
91    }
92
93    #[test]
94    fn compilation_context_can_add_multiple_diagnostics() {
95        let mut context = CompilationContext::default();
96
97        context.add_diagnostics([
98            SourceDiagnostic::new(
99                DiagnosticLevel::Warning,
100                "examples/test.ocelot",
101                "unused value",
102            ),
103            SourceDiagnostic::new(
104                DiagnosticLevel::Error,
105                "examples/test.ocelot",
106                "type mismatch",
107            ),
108        ]);
109
110        assert_eq!(context.source_diagnostics.diagnostics.len(), 2);
111        assert!(context.has_errors());
112    }
113}