donet_core/parser/
error.rs1use super::lexer::{DCToken, Span};
23use super::pipeline::{PipelineData, PipelineStage};
24use codespan_diag::Label;
25use codespan_diag::LabelStyle;
26use codespan_reporting::diagnostic as codespan_diag;
27use std::mem::discriminant;
28use thiserror::Error;
29
30pub trait ToErrorCode
33where
34 Self: std::error::Error,
35{
36 fn error_code(&self) -> &str;
37}
38
39#[derive(Debug, Error)]
40#[error(transparent)]
41pub enum DCReadError {
42 #[error("parser error")]
43 Syntax,
44 #[error("semantics error")]
45 Semantic,
46 IO(#[from] std::io::Error),
47}
48
49#[derive(Debug, Error)]
50#[error(transparent)]
51pub enum PipelineError {
52 Parser(#[from] ParseError),
53 Semantics(#[from] SemanticError),
54}
55
56impl ToErrorCode for PipelineError {
57 fn error_code(&self) -> &str {
58 match self {
60 Self::Parser(err) => err.error_code(),
61 Self::Semantics(err) => err.error_code(),
62 }
63 }
64}
65
66#[derive(Debug, Error)]
68pub enum SemanticError {
69 #[error("`{0}` is already defined")]
71 AlreadyDefined(String),
72 #[error("`{0}` is not defined")]
73 NotDefined(String),
74
75 #[error("multiple inheritance is not allowed")]
77 MultipleInheritanceDisabled,
78 #[error("maximum number of dclasses declared")]
79 DClassOverflow,
80 #[error("maximum number of fields declared")]
81 FieldOverflow,
82
83 #[error("redundant view suffix `{0}`")]
85 RedundantViewSuffix(String),
86
87 #[error("redundant keyword `{0}`")]
89 RedundantKeyword(String),
90
91 #[error("dc keywords are not allowed in struct fields")]
93 KeywordsInStructField,
94
95 #[error("duplicate case value")]
97 RedundantCase,
98 #[error("default case already defined")]
99 RedundantDefault,
100 #[error("case value type does not match key value type")]
101 InvalidCaseValueType,
102
103 #[error("`mismatched dc keywords in molecule between `{atom1}` and `{atom2}`")]
105 MismatchedKeywords { atom1: String, atom2: String },
106 #[error("`{0}` is not an atomic field")]
107 ExpectedAtomic(String),
108
109 #[error("invalid range for type")]
111 InvalidRange,
112 #[error("overlapping range")]
113 OverlappingRange,
114 #[error("value out of range")]
115 ValueOutOfRange,
116
117 #[error("invalid divisor")]
119 InvalidDivisor,
120 #[error("invalid modulus")]
121 InvalidModulus,
122
123 #[error("invalid default value for type")]
125 InvalidDefault,
126
127 #[error("`{0}` is not a struct")]
129 ExpectedStruct(String),
130}
131
132impl ToErrorCode for SemanticError {
133 fn error_code(&self) -> &str {
134 match self {
135 Self::AlreadyDefined(_) => "E0200",
137 Self::NotDefined(_) => "E0201",
138 Self::MultipleInheritanceDisabled => "E0210",
140 Self::DClassOverflow => "E0211",
141 Self::FieldOverflow => "E0212",
142 Self::RedundantViewSuffix(_) => "E0220",
144 Self::RedundantKeyword(_) => "E0230",
146 Self::KeywordsInStructField => "E0240",
148 Self::RedundantCase => "E0250",
150 Self::RedundantDefault => "E0251",
151 Self::InvalidCaseValueType => "E0252",
152 Self::MismatchedKeywords { atom1: _, atom2: _ } => "E0260",
154 Self::ExpectedAtomic(_) => "E0261",
155 Self::InvalidRange => "E0270",
157 Self::OverlappingRange => "E0271",
158 Self::ValueOutOfRange => "E0272",
159 Self::InvalidDivisor => "E0280",
161 Self::InvalidModulus => "E0281",
162 Self::InvalidDefault => "E0290",
164 Self::ExpectedStruct(_) => "E0300",
166 }
167 }
168}
169
170#[derive(Debug, Error)]
176pub enum ParseError {
177 #[error("syntax error; {1}, found `{0:?}`")]
178 Error(DCToken, String),
179}
180
181impl ToErrorCode for ParseError {
182 fn error_code(&self) -> &str {
183 match self {
184 Self::Error(_, _) => "E0100",
185 }
186 }
187}
188
189pub(crate) struct Diagnostic {
190 span: Span,
191 stage: PipelineStage,
192 file_id: usize,
193 severity: codespan_diag::Severity,
194 error: PipelineError,
195}
196
197impl Diagnostic {
198 pub fn error(span: Span, pipeline: &mut PipelineData, err: impl Into<PipelineError>) -> Self {
199 Self {
200 span,
201 stage: pipeline.current_stage(),
202 file_id: pipeline.current_file(),
203 severity: codespan_diag::Severity::Error,
204 error: err.into(),
205 }
206 }
207}
208
209impl From<Diagnostic> for codespan_diag::Diagnostic<usize> {
211 fn from(val: Diagnostic) -> codespan_diag::Diagnostic<usize> {
212 codespan_diag::Diagnostic::new(val.severity)
213 .with_message(val.error.to_string())
214 .with_code(val.error.error_code())
215 .with_labels(vec![Label::new(
216 LabelStyle::Primary,
217 val.file_id,
218 val.span.min..val.span.max,
219 )])
220 .with_notes({
221 if discriminant(&val.stage) == discriminant(&PipelineStage::Parser) {
223 vec![
224 "Syntax errors are limited. Please see issue #19.".into(),
225 "https://gitlab.com/donet-server/donet/-/issues/19".into(),
226 ]
227 } else {
228 vec![]
229 }
230 })
231 }
232}