1use std::ops::Range;
2
3use ariadne::{Color, Label, Report, Source};
4
5use crate::{
6 lexer::{Position, Token},
7 state::{ParserState, SymbolValue},
8};
9
10pub type TaleResult<T> = Result<T, TaleError>;
11
12pub type TaleResultVec<T> = Result<T, Vec<TaleError>>;
13
14#[derive(Debug, Clone)]
15pub struct TaleError {
16 kind: TaleErrorKind,
17 span: Range<usize>,
18 position: Position,
19 msg: String,
20}
21
22#[derive(Debug, Clone)]
23pub enum TaleErrorKind {
24 Lexical,
25 Parse,
26 Analysis,
27 Evaluation,
28 System,
29}
30
31impl TaleError {
32 #[must_use]
33 pub fn system(msg: String) -> Self {
34 Self {
35 kind: TaleErrorKind::System,
36 span: 0..0,
37 position: (0, 0),
38 msg,
39 }
40 }
41
42 #[must_use]
43 pub fn lexer(span: Range<usize>, position: Position, msg: String) -> Self {
44 Self {
45 kind: TaleErrorKind::Lexical,
46 span,
47 position,
48 msg,
49 }
50 }
51
52 #[must_use]
53 pub fn parser(span: Range<usize>, position: Position, msg: String) -> Self {
54 Self {
55 kind: TaleErrorKind::Parse,
56 span,
57 position,
58 msg,
59 }
60 }
61
62 #[must_use]
63 pub fn from_parser_vec(errs: Vec<chumsky::error::Rich<'_, Token>>) -> Vec<Self> {
64 errs.into_iter()
65 .map(|err| {
66 let context_list = err
68 .contexts()
69 .map(|context| context.0.to_string())
70 .collect::<Vec<_>>()
71 .join(" -> ");
72 let msg = if context_list.is_empty() {
73 err.reason().to_string()
74 } else {
75 format!("{} In: [{context_list}]", err.reason())
76 };
77 Self::parser(err.span().into_range(), Default::default(), msg)
78 })
79 .collect::<Vec<Self>>()
80 }
81
82 #[must_use]
83 pub fn update_parser_vec_with_state(mut errs: Vec<Self>, state: &ParserState) -> Vec<Self> {
84 for err in &mut errs {
85 let span = err.span();
86 err.update_span(state.get_source_span(&span));
87 err.update_position(state.get_source_position(&span));
88 }
89 errs
90 }
91
92 #[must_use]
93 pub fn analyzer(span: Range<usize>, position: Position, msg: String) -> Self {
94 Self {
95 kind: TaleErrorKind::Analysis,
96 span,
97 position,
98 msg,
99 }
100 }
101
102 #[must_use]
103 pub fn evaluator(span: Range<usize>, position: Position, msg: String) -> Self {
104 Self {
105 kind: TaleErrorKind::Evaluation,
106 span,
107 position,
108 msg,
109 }
110 }
111
112 #[must_use]
113 pub fn span(&self) -> Range<usize> {
114 self.span.clone()
115 }
116
117 pub fn update_span(&mut self, span: Range<usize>) {
118 self.span = span;
119 }
120
121 #[must_use]
122 pub fn start(&self) -> usize {
123 self.span.start
124 }
125
126 #[must_use]
127 pub fn end(&self) -> usize {
128 self.span.end
129 }
130
131 #[must_use]
132 pub fn position(&self) -> Position {
133 self.position
134 }
135
136 pub fn update_position(&mut self, position: Position) {
137 self.position = position;
138 }
139
140 pub fn append_message(&mut self, add_msg: &str) {
141 self.msg.push_str(add_msg);
142 }
143
144 #[must_use]
145 pub fn kind(&self) -> &TaleErrorKind {
146 &self.kind
147 }
148
149 #[must_use]
150 pub fn msg(&self) -> &String {
151 &self.msg
152 }
153}
154
155impl From<std::io::Error> for TaleError {
156 fn from(value: std::io::Error) -> Self {
157 Self::system(value.to_string())
158 }
159}
160
161impl From<std::num::TryFromIntError> for TaleError {
162 fn from(value: std::num::TryFromIntError) -> Self {
163 Self::evaluator(0..0, Position::default(), value.to_string())
164 }
165}
166
167impl From<TaleError> for Vec<TaleError> {
168 fn from(value: TaleError) -> Self {
169 vec![value]
170 }
171}
172
173pub fn render_tale_result_vec(
174 prefix: &str,
175 source_name: &str,
176 source: &str,
177 tale_result_vec: TaleResultVec<SymbolValue>,
178) -> TaleResultVec<SymbolValue> {
179 match tale_result_vec {
180 Ok(value) => {
181 value.render(prefix);
182 Ok(SymbolValue::Placeholder)
183 }
184 Err(tev) => render_tale_error_vec(tev, source_name, source),
185 }
186}
187
188pub fn render_tale_error_vec(
189 tev: Vec<TaleError>,
190 source_name: &str,
191 source: &str,
192) -> TaleResultVec<SymbolValue> {
193 for error in tev {
194 Report::build(ariadne::ReportKind::Error, (source_name, error.span()))
195 .with_message(format!("{:?} Error: {}", error.kind(), error.msg()))
196 .with_label(
197 Label::new((source_name, error.span()))
198 .with_message("Problem occurred here.")
199 .with_color(Color::Red),
200 )
201 .finish()
202 .eprint((source_name, Source::from(source)))
203 .map_err(TaleError::from)?;
204 }
205 Ok(SymbolValue::Placeholder)
206}