1use crate::edb::PredicateRef;
9use crate::features::Feature;
10use std::fmt::{Display, Formatter};
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct SourceLocation {
21 line: usize,
22 column: usize,
23}
24
25#[derive(Debug)]
31pub enum Error {
32 FileIoError(std::io::Error),
34
35 FormatError(std::fmt::Error),
37
38 ParserError(Box<dyn std::error::Error>),
40
41 Serialization(Box<dyn std::error::Error>),
43
44 SerializationFormatUnknown { format: String },
47
48 SerializationOperationUnsupported { format: String },
51
52 LanguageFeatureDisabled { feature: Feature },
54
55 LanguageFeatureUnsupported { feature: Feature },
57
58 InvalidValue {
60 expecting_type: String,
61 given_value: String,
62 },
63
64 FactDoesNotConformToSchema { label: PredicateRef, terms: String },
66
67 ExtensionalPredicateInRuleHead {
69 label: PredicateRef,
70 location: Option<SourceLocation>,
71 },
72
73 InvalidHeadAtomCount {
75 actual: usize,
76 min: usize,
77 max: usize,
78 location: Option<SourceLocation>,
79 },
80
81 HeadVariablesMissingInBody {
83 atom: PredicateRef,
84 variables: Vec<String>,
85 location: Option<SourceLocation>,
86 },
87
88 NegativeVariablesNotAlsoPositive {
90 atom: PredicateRef,
91 variables: Vec<String>,
92 location: Option<SourceLocation>,
93 },
94
95 ArithmeticVariablesNotAlsoPositive {
97 atom: PredicateRef,
98 variables: Vec<String>,
99 location: Option<SourceLocation>,
100 },
101
102 RelationExists { label: PredicateRef },
104
105 RelationDoesNotExist { label: PredicateRef },
107
108 AttributeDoesNotExist { label: String },
110
111 AttributeIndexInvalid { index: usize },
113
114 NotStratifiable,
116
117 NullaryFactsNotAllowed,
119
120 ComparisonIsAlwaysTrue { comparison: String },
122
123 ComparisonIsAlwaysFalse { comparison: String },
125
126 IncompatibleTypes { lhs_type: String, rhs_type: String },
128
129 AnonymousVariableNotAllowed,
131}
132
133pub type Result<T> = std::result::Result<T, Error>;
137
138#[inline]
145pub fn serialization_format_unknown<S: Into<String>>(format: S) -> Error {
146 Error::SerializationFormatUnknown {
147 format: format.into(),
148 }
149}
150
151#[inline]
154pub fn serialization_operation_unsupported<S: Into<String>>(format: S) -> Error {
155 Error::SerializationOperationUnsupported {
156 format: format.into(),
157 }
158}
159
160#[inline]
162pub fn language_feature_disabled(feature: Feature) -> Error {
163 Error::LanguageFeatureDisabled { feature }
164}
165
166#[inline]
168pub fn language_feature_unsupported(feature: Feature) -> Error {
169 Error::LanguageFeatureUnsupported { feature }
170}
171
172#[inline]
174pub fn invalid_value<S: Into<String>>(expecting_type: S, given_value: S) -> Error {
175 Error::InvalidValue {
176 expecting_type: expecting_type.into(),
177 given_value: given_value.into(),
178 }
179}
180
181#[inline]
183pub fn fact_does_not_correspond_to_schema<S: Into<String>>(label: PredicateRef, terms: S) -> Error {
184 Error::FactDoesNotConformToSchema {
185 label,
186 terms: terms.into(),
187 }
188}
189
190#[inline]
192pub fn extensional_predicate_in_rule_head(
193 label: PredicateRef,
194 location: Option<SourceLocation>,
195) -> Error {
196 Error::ExtensionalPredicateInRuleHead { label, location }
197}
198
199#[inline]
201pub fn invalid_head_atom_count(
202 actual: usize,
203 min: usize,
204 max: usize,
205 location: Option<SourceLocation>,
206) -> Error {
207 Error::InvalidHeadAtomCount {
208 actual,
209 min,
210 max,
211 location,
212 }
213}
214
215#[inline]
217pub fn head_variables_missing_in_body(
218 atom: PredicateRef,
219 variables: Vec<String>,
220 location: Option<SourceLocation>,
221) -> Error {
222 Error::HeadVariablesMissingInBody {
223 atom,
224 variables,
225 location,
226 }
227}
228
229#[inline]
231pub fn negative_variables_not_also_positive(
232 atom: PredicateRef,
233 variables: Vec<String>,
234 location: Option<SourceLocation>,
235) -> Error {
236 Error::NegativeVariablesNotAlsoPositive {
237 atom,
238 variables,
239 location,
240 }
241}
242
243#[inline]
245pub fn arithmetic_variables_not_also_positive(
246 atom: PredicateRef,
247 variables: Vec<String>,
248 location: Option<SourceLocation>,
249) -> Error {
250 Error::ArithmeticVariablesNotAlsoPositive {
251 atom,
252 variables,
253 location,
254 }
255}
256
257#[inline]
259pub fn relation_exists(label: PredicateRef) -> Error {
260 Error::RelationExists { label }
261}
262
263#[inline]
264pub fn relation_does_not_exist(label: PredicateRef) -> Error {
265 Error::RelationDoesNotExist { label }
266}
267
268#[inline]
270pub fn attribute_does_not_exist<S: Into<String>>(label: S) -> Error {
271 Error::AttributeDoesNotExist {
272 label: label.into(),
273 }
274}
275
276#[inline]
278pub fn attribute_index_invalid(index: usize) -> Error {
279 Error::AttributeIndexInvalid { index }
280}
281
282#[inline]
284pub fn program_not_stratifiable() -> Error {
285 Error::NotStratifiable
286}
287
288#[inline]
290pub fn nullary_facts_not_allowed() -> Error {
291 Error::NullaryFactsNotAllowed
292}
293
294#[inline]
296pub fn comparison_is_always_true<S: Into<String>>(comparison: S) -> Error {
297 Error::ComparisonIsAlwaysTrue {
298 comparison: comparison.into(),
299 }
300}
301
302#[inline]
304pub fn comparison_is_always_false<S: Into<String>>(comparison: S) -> Error {
305 Error::ComparisonIsAlwaysFalse {
306 comparison: comparison.into(),
307 }
308}
309
310#[inline]
312pub fn anonymous_variable_not_allowed() -> Error {
313 Error::AnonymousVariableNotAllowed
314}
315
316#[inline]
318pub fn incompatible_types<S: Into<String>>(lhs_type: S, rhs_type: S) -> Error {
319 Error::IncompatibleTypes {
320 lhs_type: lhs_type.into(),
321 rhs_type: rhs_type.into(),
322 }
323}
324
325impl From<(usize, usize)> for SourceLocation {
330 fn from(v: (usize, usize)) -> Self {
331 Self {
332 line: v.0,
333 column: v.1,
334 }
335 }
336}
337
338impl Display for SourceLocation {
339 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
340 write!(f, "[line {}, column {}]", self.line, self.column)
341 }
342}
343
344impl SourceLocation {
345 pub fn line(&self) -> usize {
347 self.line
348 }
349
350 pub fn column(&self) -> usize {
352 self.column
353 }
354}
355
356impl Display for Error {
359 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
360 write!(
361 f,
362 "{}",
363 match self {
364 Self::FileIoError(e) => format!("File IO error, {}", e),
365 Self::FormatError(e) => format!("Formatting error, {}", e),
366 Self::ParserError(e) => e.to_string(),
367 Self::InvalidValue { expecting_type, given_value } =>
368 format!("Invalid value for type {}, given {:?}", expecting_type, given_value),
369 Error::LanguageFeatureDisabled{ feature } =>
370 format!("The language feature {} is not enabled.", feature.label()),
371 Error::LanguageFeatureUnsupported{ feature } =>
372 format!("The language feature {} is not supported by the attempted operation.", feature.label()),
373 Error::ExtensionalPredicateInRuleHead { label, location } =>
374 format!("A predicate {} from the EDB was present in a rule head{}.", label, match location {
375 None => String::new(),
376 Some(src) => format!(" (at {})", src),
377 }),
378 Error::InvalidHeadAtomCount { actual, min, max, location } =>
379 format!(
380 "Rule{} has an invalid number of head atoms, {}, for current feature set. expecting {}..{}",
381 match location {
382 None => String::new(),
383 Some(src) => format!(" (at {})", src),
384 },
385 actual,
386 min,max,
387 ),
388 Error::HeadVariablesMissingInBody { atom, variables, location } =>
389 format!(
390 "In rule '{}'{}, the variable(s) '{}' in the head do not appear in any positive literal in the body.",
391 atom,
392 match location {
393 None => String::new(),
394 Some(src) => format!(" (at {})", src),
395 },
396 variables.join(", ")
397 ),
398 Error::NegativeVariablesNotAlsoPositive{ atom, variables, location } =>
399 format!(
400 "In rule '{}'{}, the variables '{}' in some negative literal(s) do not appear in any positive literal in the body.",
401 atom,
402 match location {
403 None => String::new(),
404 Some(src) => format!(", at {}", src),
405 },
406 variables.join(", ")
407 ),
408 Error::ArithmeticVariablesNotAlsoPositive{ atom, variables, location } =>
409 format!(
410 "In rule '{}'{}, the variables '{}' in some arithmetic literal(s) do not appear in any positive literal in the body.",
411 atom,
412 match location {
413 None => String::new(),
414 Some(src) => format!(", at {}", src),
415 },
416 variables.join(", ")
417 ),
418 Error::RelationExists { label } => format!("The relation '{}' already exists in the extensional database.", label),
419 Error::RelationDoesNotExist { label } => format!("The relation '{}' does not exist in the selected database.", label),
420 Error::FactDoesNotConformToSchema { label, terms } => format!("The fact values ({}) do not meet the schema requirements for relation '{}'", terms, label),
421 Error::Serialization(e) => format!("An error occured either serializing or deserializing a relation: {}", e),
422 Error::SerializationFormatUnknown { format: serialization } => format!("'{}' is not a supported serialization format.", serialization),
423 Error::SerializationOperationUnsupported{ format: serialization } => format!("The requested I/O operation is not supported by the serialization format '{}'", serialization),
424 Error::NotStratifiable => "The program cannot be evaluated as it includes negation but cannot be stratified.".to_string(),
425 Error::AttributeDoesNotExist { label } => format!("The attribute labeled '{}' was not a member of the relation or view schema.", label),
426 Error::AttributeIndexInvalid { index } => format!("The attribute index '{}' is not valid for the relation or view schema.", index),
427 Error::NullaryFactsNotAllowed => "The arity of facts must be greater than, or equal to, 1.".to_string(),
428 Error::ComparisonIsAlwaysTrue { comparison } => format!("A comparison operator, or selection criteria, will always be true/⊤ (`{}`).", comparison),
429 Error::ComparisonIsAlwaysFalse { comparison } => format!("A comparison operator, or selection criteria, will always be false/⊥ (`{}`).", comparison),
430 Error::AnonymousVariableNotAllowed => "Anonymous variables not allowed in the current context.".to_string(),
431 Error::IncompatibleTypes { lhs_type, rhs_type } => format!("A requested operation cannot be performed as the values have incompatible types `{}`, `{}`.", lhs_type, rhs_type),
432 }
433 )
434 }
435}
436
437impl std::error::Error for Error {
438 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
439 match *self {
440 Self::FileIoError(ref e) => Some(e),
441 _ => None,
442 }
443 }
444}
445
446impl From<std::io::Error> for Error {
447 fn from(e: std::io::Error) -> Self {
448 Self::FileIoError(e)
449 }
450}
451
452impl From<std::fmt::Error> for Error {
453 fn from(e: std::fmt::Error) -> Self {
454 Self::FormatError(e)
455 }
456}
457
458impl<T> From<Error> for Result<T> {
459 fn from(v: Error) -> Self {
460 Err(v)
461 }
462}
463
464impl Error {}