1use std::{error::Error, fmt};
2
3#[derive(Debug, PartialEq, Eq)]
5pub struct ParseError {
6 pub original: String,
8 pub span: std::ops::Range<usize>,
11 pub reason: Reason,
13}
14
15#[derive(Debug, PartialEq, Eq)]
17pub enum Reason {
18 InvalidNot(usize),
20 InvalidCharacters,
22 UnclosedParens,
24 UnopenedParens,
26 UnclosedQuotes,
28 UnopenedQuotes,
30 Empty,
32 Unexpected(&'static [&'static str]),
35 InvalidInteger,
37 MultipleRootPredicates,
39 InvalidHasAtomic,
41 UnknownBuiltin,
43}
44
45impl fmt::Display for ParseError {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 f.write_str(&self.original)?;
48 f.write_str("\n")?;
49
50 for _ in 0..self.span.start {
51 f.write_str(" ")?;
52 }
53
54 match &self.reason {
57 r @ (Reason::UnclosedParens | Reason::UnclosedQuotes) => {
58 f.write_fmt(format_args!("- {r}"))
59 }
60 r @ (Reason::UnopenedParens | Reason::UnopenedQuotes) => {
61 f.write_fmt(format_args!("^ {r}"))
62 }
63 other => {
64 for _ in self.span.start..self.span.end {
65 f.write_str("^")?;
66 }
67
68 f.write_fmt(format_args!(" {other}"))
69 }
70 }
71 }
72}
73
74impl fmt::Display for Reason {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 use Reason::{
77 Empty, InvalidCharacters, InvalidHasAtomic, InvalidInteger, InvalidNot,
78 MultipleRootPredicates, UnclosedParens, UnclosedQuotes, Unexpected, UnknownBuiltin,
79 UnopenedParens, UnopenedQuotes,
80 };
81
82 match self {
83 InvalidCharacters => f.write_str("invalid character(s)"),
84 UnclosedParens => f.write_str("unclosed parens"),
85 UnopenedParens => f.write_str("unopened parens"),
86 UnclosedQuotes => f.write_str("unclosed quotes"),
87 UnopenedQuotes => f.write_str("unopened quotes"),
88 Empty => f.write_str("empty expression"),
89 Unexpected(expected) => {
90 if expected.len() > 1 {
91 f.write_str("expected one of ")?;
92
93 for (i, exp) in expected.iter().enumerate() {
94 f.write_fmt(format_args!("{}`{exp}`", if i > 0 { ", " } else { "" }))?;
95 }
96 f.write_str(" here")
97 } else if !expected.is_empty() {
98 f.write_fmt(format_args!("expected a `{}` here", expected[0]))
99 } else {
100 f.write_str("the term was not expected here")
101 }
102 }
103 InvalidNot(np) => f.write_fmt(format_args!("not() takes 1 predicate, found {np}")),
104 InvalidInteger => f.write_str("invalid integer"),
105 MultipleRootPredicates => f.write_str("multiple root predicates"),
106 InvalidHasAtomic => f.write_str("expected integer or \"ptr\""),
107 UnknownBuiltin => f.write_str("unknown built-in"),
108 }
109 }
110}
111
112impl Error for ParseError {
113 fn description(&self) -> &str {
114 use Reason::{
115 Empty, InvalidCharacters, InvalidHasAtomic, InvalidInteger, InvalidNot,
116 MultipleRootPredicates, UnclosedParens, UnclosedQuotes, Unexpected, UnknownBuiltin,
117 UnopenedParens, UnopenedQuotes,
118 };
119
120 match self.reason {
121 InvalidCharacters => "invalid character(s)",
122 UnclosedParens => "unclosed parens",
123 UnopenedParens => "unopened parens",
124 UnclosedQuotes => "unclosed quotes",
125 UnopenedQuotes => "unopened quotes",
126 Empty => "empty expression",
127 Unexpected(_) => "unexpected term",
128 InvalidNot(_) => "not() takes 1 predicate",
129 InvalidInteger => "invalid integer",
130 MultipleRootPredicates => "multiple root predicates",
131 InvalidHasAtomic => "expected integer or \"ptr\"",
132 UnknownBuiltin => "unknown built-in",
133 }
134 }
135}
136
137#[derive(Clone, Debug, Eq, PartialEq)]
139pub struct HasAtomicParseError {
140 pub(crate) input: String,
141}
142
143impl fmt::Display for HasAtomicParseError {
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 write!(f, "expected integer or \"ptr\", found {}", self.input)
146 }
147}
148
149impl Error for HasAtomicParseError {}