scdlang/error/
util.rs

1use super::{Error, PestError};
2use crate::Scdlang;
3use pest::{
4	error::{ErrorVariant::CustomError, InputLocation},
5	Position, Span,
6};
7use std::{error, fmt, iter};
8
9//TODO: make PR on pest for defining offset so that param `source` can be omitted
10pub(crate) trait Offset: error::Error {
11	fn with_offset(self, offset: usize, source: &str) -> Self;
12}
13
14impl<'t> Scdlang<'t> {
15	/// Used to beutifully format semantics error from span
16	pub(crate) fn err_from_span(&self, span: Span, message: String) -> PestError {
17		let source = span.as_str();
18		self.reformat_error(source, PestError::new_from_span(CustomError { message }, span))
19	}
20}
21
22impl Offset for PestError {
23	fn with_offset(self, offset: usize, source: &str) -> Self {
24		match self.location {
25			InputLocation::Span((start, end)) => PestError::new_from_span(
26				self.variant,
27				Span::new(
28					&format!(
29						"{offset}{src}",
30						offset = iter::repeat('\n').take(offset).collect::<String>(),
31						src = source
32					),
33					start + offset,
34					end + offset,
35				)
36				.expect("Index (offset) must NOT out of bound"),
37			),
38			InputLocation::Pos(line) => PestError::new_from_pos(
39				self.variant,
40				Position::new(
41					&format!(
42						"{offset}{src}",
43						offset = iter::repeat('\n').take(offset).collect::<String>(),
44						src = source
45					),
46					line + offset,
47				)
48				.expect("Index (offset) must NOT out of bound"),
49			),
50		}
51	}
52}
53
54impl From<PestError> for Error {
55	fn from(err: PestError) -> Self {
56		Error::Parse(err.into())
57	}
58}
59
60impl error::Error for Error {}
61impl fmt::Display for Error {
62	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63		match self {
64			Error::Parse(err) => write!(f, "{}", err),
65			_ => write!(f, "{:#?}", self), // TODO: make it fluent and verbose 😅
66		}
67	}
68}