yolk/script/
rhai_error.rs1use std::ops::Range;
2
3use miette::Diagnostic;
4
5#[derive(Debug, thiserror::Error, Diagnostic)]
6pub enum RhaiError {
7 #[error("{origin}")]
8 #[diagnostic(forward(origin))]
9 SourceError {
10 #[label("here")]
11 span: Range<usize>,
12 origin: Box<RhaiError>,
13 },
14 #[error(transparent)]
15 RhaiError(#[from] rhai::EvalAltResult),
16 #[error("{}", .0)]
17 #[diagnostic(transparent)]
18 Other(miette::Report),
19}
20
21impl RhaiError {
22 pub fn new_other<E>(err: E) -> Self
23 where
24 E: std::error::Error + Send + Sync + 'static,
25 {
26 Self::Other(miette::miette!(err))
27 }
28 pub fn other<E>(err: E) -> Self
29 where
30 E: Diagnostic + Send + Sync + 'static,
31 {
32 Self::Other(miette::Report::from(err))
33 }
34
35 pub fn from_rhai_compile(source_code: &str, err: rhai::ParseError) -> Self {
36 Self::from_rhai(source_code, err.into())
37 }
38
39 pub fn from_rhai(source_code: &str, err: rhai::EvalAltResult) -> Self {
40 let position = err.position();
41 let mut span = 0..0;
42 if let Some(line_nr) = position.line() {
43 let offset_start = source_code
45 .split_inclusive('\n')
46 .take(line_nr - 1)
47 .map(|x| x.len())
48 .sum::<usize>();
49 span = if let Some(within_line) = position.position() {
50 offset_start + within_line..offset_start + within_line + 1
51 } else {
52 let offset_end = offset_start
53 + source_code
54 .lines()
55 .nth(line_nr - 1)
56 .map(|x| x.len())
57 .unwrap_or_default();
58 let indent = source_code[offset_start..]
59 .chars()
60 .take_while(|x| x.is_whitespace())
61 .count();
62 offset_start + indent..offset_end
63 };
64 }
65 if span.start >= source_code.len() {
66 span = source_code.len() - 1..source_code.len();
67 }
68 Self::SourceError {
69 span,
70 origin: Box::new(RhaiError::RhaiError(err)),
71 }
72 }
73
74 pub fn into_report(self, name: impl ToString, source: impl ToString) -> miette::Report {
76 miette::Report::from(self).with_source_code(
77 miette::NamedSource::new(name.to_string(), source.to_string()).with_language("Rust"),
78 )
79 }
80}