1use std::fmt::Debug;
2
3use pest::iterators::Pair;
4
5use crate::Rule;
6
7pub type AstResult<'a, T, ET = T> = Result<T, AstError<'a, ET>>;
8
9#[derive(Debug, Clone)]
10pub enum ParseError<'a, T> {
11 PreAst(pest::error::Error<Rule>),
12 Ast(AstError<'a, T>),
13}
14
15#[derive(Debug, Clone)]
16pub struct AstError<'a, T> {
17 pub span: pest::Span<'a>,
18 pub error_code: ErrorCode,
19 pub error_message: String,
20 pub recovered: Option<T>,
21}
22
23#[derive(Debug, Clone)]
24pub enum ErrorCode {
25 InvalidStatement,
26 AstGenBug,
27}
28
29impl<T> From<pest::error::Error<Rule>> for ParseError<'_, T> {
30 fn from(value: pest::error::Error<Rule>) -> Self {
31 Self::PreAst(value)
32 }
33}
34
35impl<'a, T> From<AstError<'a, T>> for ParseError<'a, T> {
36 fn from(value: AstError<'a, T>) -> Self {
37 Self::Ast(value)
38 }
39}
40
41impl<'a, F> AstError<'a, F> {
42 pub fn get<T>(self) -> AstError<'a, T> {
43 AstError {
44 span: self.span,
45 error_code: self.error_code,
46 error_message: self.error_message,
47 recovered: None,
48 }
49 }
50
51 pub fn bug_unimplemented<T>(pair: Pair<'a, Rule>) -> AstResult<'a, T, F> {
52 Err(Self {
53 span: pair.as_span(),
54 error_code: ErrorCode::AstGenBug,
55 error_message: format!("Possible bug, unimplemented: {:#?}", pair.as_rule()),
56 recovered: None,
57 })
58 }
59}
60
61pub trait IntoErr<T, FA, FR> {
62 fn get(self) -> T;
63 fn get_map(self, m: impl Fn(FA) -> FR) -> T;
64}
65
66impl<'a, T, TE, TE2> IntoErr<AstResult<'a, T, TE2>, TE, TE2> for AstResult<'a, T, TE> {
67 fn get(self) -> AstResult<'a, T, TE2> {
68 self.map_err(AstError::get)
69 }
70
71 fn get_map(self, m: impl Fn(TE) -> TE2) -> AstResult<'a, T, TE2> {
72 self.map_err(|e| AstError {
73 span: e.span,
74 error_code: e.error_code,
75 error_message: e.error_message,
76 recovered: e.recovered.map(m),
77 })
78 }
79}
80
81pub trait GetLength {
82 fn len(&self) -> usize;
83}
84
85impl<T, E> GetLength for Result<Vec<T>, E> {
86 fn len(&self) -> usize {
87 if let Ok(v) = self { v.len() } else { 0 }
88 }
89}
90
91pub fn collect_recovered<'a, T: Debug, ET>(
92 pairs: impl Iterator<Item = pest::iterators::Pair<'a, Rule>>,
93) -> AstResult<'a, Vec<T>, Vec<T>>
94where
95 T: TryFrom<pest::iterators::Pair<'a, Rule>, Error = AstError<'a, ET>>,
96{
97 collect_recovered_map(pairs, T::try_from)
98}
99
100pub fn collect_recovered_map<'a, T: Debug, F, ET>(
101 pairs: impl Iterator<Item = pest::iterators::Pair<'a, Rule>>,
102 f: F,
103) -> AstResult<'a, Vec<T>, Vec<T>>
104where
105 F: Fn(pest::iterators::Pair<'a, Rule>) -> AstResult<'a, T, ET>,
106{
107 let mut items = Vec::new();
108 let mut last_error: Option<AstError<'a, ET>> = None;
109
110 for pair in pairs {
111 match f(pair) {
112 Ok(item) => items.push(item),
113 Err(e) => {
114 last_error = Some(e);
115 }
116 }
117 }
118
119 match last_error {
120 Some(ast_err) => Err(AstError {
121 span: ast_err.span,
122 error_code: ast_err.error_code,
123 error_message: ast_err.error_message,
124 recovered: Some(items),
125 }),
126 None => Ok(items),
127 }
128}
129
130pub struct AstErrorAnalyzer<'a, T>(pub Option<AstError<'a, T>>);
131
132impl<'a, T> AstErrorAnalyzer<'a, T> {
133 pub fn get<V: Clone, V2: Clone + Into<V>>(
134 &mut self,
135 r: AstResult<'a, V, V2>,
136 ) -> AstResult<'a, V, V2> {
137 if let Err(e) = r {
138 self.0 = Some(e.clone().get());
139
140 if let Some(recovered) = e.recovered {
141 Ok(recovered.into())
142 } else {
143 Err(e)
144 }
145 } else {
146 r
147 }
148 }
149
150 pub fn build(self, v: T) -> AstResult<'a, T> {
151 if let Some(mut e) = self.0 {
152 e.recovered = Some(v);
153
154 Err(e)
155 } else {
156 Ok(v)
157 }
158 }
159}