microcad_lang/parse/
parse_error.rs1use std::iter::once;
7use miette::{Diagnostic, LabeledSpan, SourceCode};
8use crate::{parse::*, ty::*};
9use thiserror::Error;
10
11#[derive(Debug, Error)]
13pub enum ParseError {
14 #[error("Error parsing floating point literal: {0}")]
16 ParseFloatError(Refer<std::num::ParseFloatError>),
17
18 #[error("Error parsing integer literal: {0}")]
20 ParseIntError(Refer<std::num::ParseIntError>),
21
22 #[error("Rule not found: {0:?}")]
24 RuleNotFoundError(Box<crate::parser::Rule>),
25
26 #[error("IO Error: {0}")]
28 IoError(Refer<std::io::Error>),
29
30 #[error("Parser error: {}", .0.variant.message())]
32 Parser(Box<pest::error::Error<crate::parser::Rule>>),
33
34 #[error("Error parsing color: {0}")]
36 ParseColorError(Refer<microcad_core::ParseColorError>),
37
38 #[error("Unknown color: {0}")]
40 UnknownColorName(Refer<String>),
41
42 #[error("Unknown unit: {0}")]
44 UnknownUnit(Refer<String>),
45
46 #[error("Unexpected token")]
48 UnexpectedToken(SrcRef),
49
50 #[error("Tuple expression contains both named and positional arguments")]
52 MixedTupleArguments(SrcRef),
53
54 #[error("Duplicate named argument: {0}")]
56 DuplicateNamedArgument(Identifier),
57
58 #[error("Positional argument after named argument")]
60 PositionalArgumentAfterNamed(SrcRef),
61
62 #[error("Empty tuple expression")]
64 EmptyTupleExpression(SrcRef),
65
66 #[error("Missing type or value for definition parameter: {0}")]
68 ParameterMissingTypeOrValue(Identifier),
69
70 #[error("Duplicate parameter: {0}")]
72 DuplicateParameter(Identifier),
73
74 #[error("Duplicate argument: {0}")]
76 DuplicateArgument(Identifier),
77
78 #[error("Duplicated type name in map: {0}")]
80 DuplicatedMapType(Identifier),
81
82 #[error("Duplicate id: {0}")]
84 DuplicateIdentifier(Identifier),
85
86 #[error("Duplicate id in tuple: {0}")]
88 DuplicateTupleIdentifier(Identifier),
89
90 #[error("Duplicate unnamed type in tuple: {0}")]
92 DuplicateTupleType(Refer<Type>),
93
94 #[error("Missing format expression")]
96 MissingFormatExpression(SrcRef),
97
98 #[error("Statement between two init statements")]
100 StatementBetweenInit(SrcRef),
101
102 #[error("Loading of source file {1:?} failed: {2}")]
104 LoadSource(SrcRef, std::path::PathBuf, std::io::Error),
105
106 #[error("Grammar rule error {0}")]
108 GrammarRuleError(Refer<String>),
109
110 #[error("Invalid qualified name '{0}'")]
112 InvalidQualifiedName(Refer<String>),
113
114 #[error("Invalid id '{0}'")]
116 InvalidIdentifier(Refer<String>),
117
118 #[error("Qualified name {0} cannot be converted into an Id")]
120 QualifiedNameIsNoId(QualifiedName),
121
122 #[error("Element is not available")]
124 NotAvailable(SrcRef),
125
126 #[error("Unknown type: {0}")]
128 UnknownType(Refer<String>),
129
130 #[error("If expression must return a value in all cases")]
132 IncompleteIfExpression(SrcRef)
133}
134
135pub type ParseResult<T> = Result<T, ParseError>;
137
138impl SrcReferrer for ParseError {
139 fn src_ref(&self) -> SrcRef {
140 match self {
141 ParseError::Parser(error) => SrcRef::new(
142 match error.location {
143 pest::error::InputLocation::Pos(pos) => std::ops::Range {
144 start: pos,
145 end: pos,
146 },
147 pest::error::InputLocation::Span((start, end)) => {
148 std::ops::Range { start, end }
149 }
150 },
151 match error.line_col {
152 pest::error::LineColLocation::Pos(pos) => pos.0,
153 pest::error::LineColLocation::Span(start, _) => start.0,
154 },
155 match error.line_col {
156 pest::error::LineColLocation::Pos(pos) => pos.1,
157 pest::error::LineColLocation::Span(start, _) => start.1,
158 },
159 0,
160 ),
161 ParseError::DuplicateNamedArgument(id)
162 | ParseError::ParameterMissingTypeOrValue(id)
163 | ParseError::DuplicateParameter(id)
164 | ParseError::DuplicateArgument(id)
165 | ParseError::DuplicatedMapType(id)
166 | ParseError::DuplicateIdentifier(id)
167 | ParseError::DuplicateTupleIdentifier(id) => id.src_ref(),
168 ParseError::QualifiedNameIsNoId(name) => name.src_ref(),
169 ParseError::UnexpectedToken(src_ref)
170 | ParseError::MixedTupleArguments(src_ref)
171 | ParseError::PositionalArgumentAfterNamed(src_ref)
172 | ParseError::EmptyTupleExpression(src_ref)
173 | ParseError::MissingFormatExpression(src_ref)
174 | ParseError::StatementBetweenInit(src_ref)
175 | ParseError::NotAvailable(src_ref)
176 | ParseError::IncompleteIfExpression(src_ref)
177 | ParseError::LoadSource(src_ref , ..) => src_ref.clone(),
178 ParseError::ParseFloatError(parse_float_error) => parse_float_error.src_ref(),
179 ParseError::ParseIntError(parse_int_error) => parse_int_error.src_ref(),
180 ParseError::RuleNotFoundError(_) => SrcRef(None),
181 ParseError::IoError(error) => error.src_ref(),
182 ParseError::ParseColorError(parse_color_error) => parse_color_error.src_ref(),
183 ParseError::UnknownColorName(name) => name.src_ref(),
184 ParseError::UnknownUnit(unit) => unit.src_ref(),
185 ParseError::DuplicateTupleType(ty) => ty.src_ref(),
186 ParseError::GrammarRuleError(rule) => rule.src_ref(),
187 ParseError::InvalidQualifiedName(name) => name.src_ref(),
188 ParseError::InvalidIdentifier(id) => id.src_ref(),
189 ParseError::UnknownType(ty) => ty.src_ref(),
190 }
191 }
192}
193
194impl ParseError {
195 pub fn with_source(self, source: String) -> ParseErrorWithSource {
197 ParseErrorWithSource {
198 error: self,
199 source_code: Some(source),
200 }
201 }
202}
203
204impl Diagnostic for ParseError {
205 fn labels(&self) -> Option<Box<dyn Iterator<Item=LabeledSpan> + '_>> {
206 let src_ref = self.src_ref().0?;
207 let message = match self {
208 ParseError::Parser(err) => {
209 err.variant.message().to_string()
210 }
211 _ => self.to_string()
212 };
213 let label = LabeledSpan::new(
214 Some(message),
215 src_ref.range.start,
216 src_ref.range.len(),
217 );
218 Some(Box::new(once(label)))
219 }
220}
221
222#[derive(Debug, Error)]
224#[error("{error}")]
225pub struct ParseErrorWithSource {
226 error: ParseError,
227 source_code: Option<String>,
228}
229
230impl From<ParseError> for ParseErrorWithSource {
231 fn from(value: ParseError) -> Self {
232 ParseErrorWithSource {
233 error: value,
234 source_code: None,
235 }
236 }
237}
238
239impl Diagnostic for ParseErrorWithSource {
240 fn source_code(&self) -> Option<&dyn SourceCode> {
241 self.source_code.as_ref().map(|source| source as &dyn SourceCode)
242 }
243
244 fn labels(&self) -> Option<Box<dyn Iterator<Item=LabeledSpan> + '_>> {
245 self.error.labels()
246 }
247}
248
249impl SrcReferrer for ParseErrorWithSource {
250 fn src_ref(&self) -> SrcRef {
251 self.error.src_ref()
252 }
253}