tensorlogic_compiler/error_recovery/
strategy.rs1use super::diagnostic::Severity;
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
24pub enum RecoveryStrategy {
25 #[default]
31 SkipOnError,
32
33 SkipOnFatal,
36
37 AbortOnAny,
44}
45
46impl RecoveryStrategy {
47 pub fn decide(self, severity: Severity) -> RecoveryAction {
49 match (self, severity) {
50 (_, Severity::Info) | (_, Severity::Warning) => RecoveryAction::Continue,
52
53 (RecoveryStrategy::SkipOnError, Severity::Error) => RecoveryAction::SkipExpression,
55 (RecoveryStrategy::SkipOnError, Severity::Fatal) => RecoveryAction::SkipExpression,
56
57 (RecoveryStrategy::SkipOnFatal, Severity::Error) => RecoveryAction::SkipExpression,
59 (RecoveryStrategy::SkipOnFatal, Severity::Fatal) => RecoveryAction::AbortProgram,
60
61 (RecoveryStrategy::AbortOnAny, Severity::Error) => RecoveryAction::AbortProgram,
63 (RecoveryStrategy::AbortOnAny, Severity::Fatal) => RecoveryAction::AbortProgram,
64 }
65 }
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
70pub enum RecoveryAction {
71 Continue,
73 SkipExpression,
76 AbortProgram,
78}
79
80impl RecoveryAction {
81 pub fn is_abort(self) -> bool {
83 matches!(self, RecoveryAction::AbortProgram)
84 }
85
86 pub fn drops_expression(self) -> bool {
88 matches!(
89 self,
90 RecoveryAction::SkipExpression | RecoveryAction::AbortProgram
91 )
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn default_is_skip_on_error() {
101 assert_eq!(RecoveryStrategy::default(), RecoveryStrategy::SkipOnError);
102 }
103
104 #[test]
105 fn skip_on_error_never_aborts() {
106 let s = RecoveryStrategy::SkipOnError;
107 assert_eq!(s.decide(Severity::Info), RecoveryAction::Continue);
108 assert_eq!(s.decide(Severity::Warning), RecoveryAction::Continue);
109 assert_eq!(s.decide(Severity::Error), RecoveryAction::SkipExpression);
110 assert_eq!(s.decide(Severity::Fatal), RecoveryAction::SkipExpression);
111 }
112
113 #[test]
114 fn skip_on_fatal_aborts_only_on_fatal() {
115 let s = RecoveryStrategy::SkipOnFatal;
116 assert_eq!(s.decide(Severity::Warning), RecoveryAction::Continue);
117 assert_eq!(s.decide(Severity::Error), RecoveryAction::SkipExpression);
118 assert_eq!(s.decide(Severity::Fatal), RecoveryAction::AbortProgram);
119 }
120
121 #[test]
122 fn abort_on_any_aborts_on_both_error_and_fatal() {
123 let s = RecoveryStrategy::AbortOnAny;
124 assert_eq!(s.decide(Severity::Info), RecoveryAction::Continue);
125 assert_eq!(s.decide(Severity::Warning), RecoveryAction::Continue);
126 assert_eq!(s.decide(Severity::Error), RecoveryAction::AbortProgram);
127 assert_eq!(s.decide(Severity::Fatal), RecoveryAction::AbortProgram);
128 }
129
130 #[test]
131 fn action_classifiers() {
132 assert!(RecoveryAction::AbortProgram.is_abort());
133 assert!(!RecoveryAction::SkipExpression.is_abort());
134 assert!(!RecoveryAction::Continue.is_abort());
135
136 assert!(!RecoveryAction::Continue.drops_expression());
137 assert!(RecoveryAction::SkipExpression.drops_expression());
138 assert!(RecoveryAction::AbortProgram.drops_expression());
139 }
140}