1use crate::ast::Span;
2use std::fmt;
3use std::sync::Arc;
4
5#[derive(Debug, Clone)]
7pub struct ErrorDetails {
8 pub message: String,
9 pub span: Span,
10 pub source_id: String,
11 pub source_text: Arc<str>,
12 pub doc_name: String,
13 pub doc_start_line: usize,
14 pub suggestion: Option<String>,
15}
16
17#[derive(Debug, Clone)]
19pub enum LemmaError {
20 Parse(Box<ErrorDetails>),
22
23 Semantic(Box<ErrorDetails>),
25
26 Runtime(Box<ErrorDetails>),
28
29 Engine(String),
31
32 CircularDependency(String),
34
35 ResourceLimitExceeded {
37 limit_name: String,
38 limit_value: String,
39 actual_value: String,
40 suggestion: String,
41 },
42
43 MultipleErrors(Vec<LemmaError>),
45}
46
47impl LemmaError {
48 pub fn parse(
50 message: impl Into<String>,
51 span: Span,
52 source_id: impl Into<String>,
53 source_text: Arc<str>,
54 doc_name: impl Into<String>,
55 doc_start_line: usize,
56 ) -> Self {
57 Self::Parse(Box::new(ErrorDetails {
58 message: message.into(),
59 span,
60 source_id: source_id.into(),
61 source_text,
62 doc_name: doc_name.into(),
63 doc_start_line,
64 suggestion: None,
65 }))
66 }
67
68 pub fn parse_with_suggestion(
70 message: impl Into<String>,
71 span: Span,
72 source_id: impl Into<String>,
73 source_text: Arc<str>,
74 doc_name: impl Into<String>,
75 doc_start_line: usize,
76 suggestion: impl Into<String>,
77 ) -> Self {
78 Self::Parse(Box::new(ErrorDetails {
79 message: message.into(),
80 span,
81 source_id: source_id.into(),
82 source_text,
83 doc_name: doc_name.into(),
84 doc_start_line,
85 suggestion: Some(suggestion.into()),
86 }))
87 }
88
89 pub fn semantic(
91 message: impl Into<String>,
92 span: Span,
93 source_id: impl Into<String>,
94 source_text: Arc<str>,
95 doc_name: impl Into<String>,
96 doc_start_line: usize,
97 ) -> Self {
98 Self::Semantic(Box::new(ErrorDetails {
99 message: message.into(),
100 span,
101 source_id: source_id.into(),
102 source_text,
103 doc_name: doc_name.into(),
104 doc_start_line,
105 suggestion: None,
106 }))
107 }
108
109 pub fn semantic_with_suggestion(
111 message: impl Into<String>,
112 span: Span,
113 source_id: impl Into<String>,
114 source_text: Arc<str>,
115 doc_name: impl Into<String>,
116 doc_start_line: usize,
117 suggestion: impl Into<String>,
118 ) -> Self {
119 Self::Semantic(Box::new(ErrorDetails {
120 message: message.into(),
121 span,
122 source_id: source_id.into(),
123 source_text,
124 doc_name: doc_name.into(),
125 doc_start_line,
126 suggestion: Some(suggestion.into()),
127 }))
128 }
129}
130
131impl fmt::Display for LemmaError {
132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 match self {
134 LemmaError::Parse(details) => {
135 write!(f, "Parse error: {}", details.message)?;
136 if let Some(suggestion) = &details.suggestion {
137 write!(f, " (suggestion: {})", suggestion)?;
138 }
139 write!(
140 f,
141 " at {}:{}:{}",
142 details.source_id, details.span.line, details.span.col
143 )
144 }
145 LemmaError::Semantic(details) => {
146 write!(f, "Semantic error: {}", details.message)?;
147 if let Some(suggestion) = &details.suggestion {
148 write!(f, " (suggestion: {})", suggestion)?;
149 }
150 write!(
151 f,
152 " at {}:{}:{}",
153 details.source_id, details.span.line, details.span.col
154 )
155 }
156 LemmaError::Runtime(details) => {
157 write!(f, "Runtime error: {}", details.message)?;
158 if let Some(suggestion) = &details.suggestion {
159 write!(f, " (suggestion: {})", suggestion)?;
160 }
161 write!(
162 f,
163 " at {}:{}:{}",
164 details.source_id, details.span.line, details.span.col
165 )
166 }
167 LemmaError::Engine(msg) => write!(f, "Engine error: {}", msg),
168 LemmaError::CircularDependency(msg) => write!(f, "Circular dependency: {}", msg),
169 LemmaError::ResourceLimitExceeded {
170 limit_name,
171 limit_value,
172 actual_value,
173 suggestion,
174 } => {
175 write!(
176 f,
177 "Resource limit exceeded: {} (limit: {}, actual: {}). {}",
178 limit_name, limit_value, actual_value, suggestion
179 )
180 }
181 LemmaError::MultipleErrors(errors) => {
182 writeln!(f, "Multiple errors:")?;
183 for (i, error) in errors.iter().enumerate() {
184 write!(f, " {}. {}", i + 1, error)?;
185 if i < errors.len() - 1 {
186 writeln!(f)?;
187 }
188 }
189 Ok(())
190 }
191 }
192 }
193}
194
195impl std::error::Error for LemmaError {}
196
197impl From<std::fmt::Error> for LemmaError {
198 fn from(err: std::fmt::Error) -> Self {
199 LemmaError::Engine(format!("Format error: {}", err))
200 }
201}