1use crate::text::Kind;
6use crate::text::PositionnedString;
7use crate::text::Word;
8
9use melodium_common::descriptor::Status;
10use melodium_engine::LogicError;
11use std::error::Error;
12use std::fmt::{Display, Formatter};
13use std::sync::Arc;
14
15#[derive(Debug, Clone)]
22pub struct ScriptError {
23 pub id: u32,
25 pub kind: ScriptErrorKind,
27}
28
29#[derive(Debug, Clone)]
31pub enum ScriptErrorKind {
32 Word {
34 word: Word,
35 expected: &'static [Kind],
36 },
37 EndOfScript,
39 DescriptionElementExpected {
40 word: Word,
41 element: Word,
42 expected: &'static [&'static str],
43 },
44 DeclarationExpected {
45 word: Word,
46 expected: &'static [&'static str],
47 },
48 InvalidRoot {
49 text: PositionnedString,
50 root: String,
51 },
52 AlreadyUsedName {
53 text: PositionnedString,
54 },
55 InvalidType {
56 text: PositionnedString,
57 },
58 InvalidStructure {
59 text: PositionnedString,
60 },
61 UnimportedElement {
62 text: PositionnedString,
63 },
64 AlreadyDeclared {
65 text: PositionnedString,
66 },
67 AlreadyAssigned {
68 text: PositionnedString,
69 },
70 MissingType {
71 text: PositionnedString,
72 },
73 MissingValue {
74 text: PositionnedString,
75 },
76 DefaultForbidden {
77 text: PositionnedString,
78 },
79 DefaultForbiddenForGenerics {
80 text: PositionnedString,
81 generic: String,
82 },
83 ConstDeclarationOnly {
84 text: PositionnedString,
85 },
86 FlowForbidden {
87 text: PositionnedString,
88 },
89 StructureForbidden {
90 text: PositionnedString,
91 },
92 TypeForbidden {
93 text: PositionnedString,
94 },
95 ConnectionMustTransmit {
96 from: PositionnedString,
97 to: PositionnedString,
98 },
99 TreatmentNotFound {
100 text: PositionnedString,
101 },
102 NameRequired {
103 text: PositionnedString,
104 },
105 UndeclaredModel {
106 text: PositionnedString,
107 },
108 UndeclaredParameter {
109 text: PositionnedString,
110 },
111 UndeclaredContext {
112 text: PositionnedString,
113 },
114 UndeclaredData {
115 text: PositionnedString,
116 },
117 ReferenceUnset {
118 debug_reference: String,
119 },
120 InvalidBoolean {
121 text: PositionnedString,
122 },
123 InvalidNumber {
124 text: PositionnedString,
125 },
126 InvalidString {
127 text: PositionnedString,
128 },
129 InvalidCharacter {
130 text: PositionnedString,
131 },
132 InvalidByte {
133 text: PositionnedString,
134 },
135 ExecutiveRestitutionFailed {
136 text: PositionnedString,
137 message: String,
138 },
139 MissingFunctionParameter {
140 text: PositionnedString,
141 index: usize,
142 },
143 MissingFunctionGeneric {
144 text: PositionnedString,
145 index: usize,
146 },
147 MissingTreatmentGeneric {
148 text: PositionnedString,
149 },
150 InvalidGeneric {
151 text: PositionnedString,
152 },
153 InvalidTrait {
154 text: PositionnedString,
155 },
156 UnexistingDependency {
157 text: PositionnedString,
158 root: String,
159 },
160 Logic {
162 error: LogicError,
163 },
164 NoDescriptor {
166 name: PositionnedString,
167 },
168}
169
170impl Display for ScriptErrorKind {
171 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
172 match self {
173 ScriptErrorKind::Word { word, expected } => write!(
174 f,
175 "found '{}' at line {} position {}, expecting {}",
176 word.text, word.position.line_number, word.position.line_position, expected.iter().map(|k| k.to_string()).collect::<Vec<_>>().join(", ")
177 ),
178 ScriptErrorKind::EndOfScript => write!(f, "reached unexpected end of script"),
179 ScriptErrorKind::DescriptionElementExpected {
180 word,
181 element,
182 expected,
183 } => write!(
184 f,
185 "for '{}' at line {} position {}, '{}' is not an expected element; {} are admitted",
186 element.text,
187 word.position.line_number,
188 word.position.line_position,
189 word.text,
190 expected
191 .iter()
192 .map(|s| format!("'{s}'"))
193 .collect::<Vec<_>>()
194 .join(", ")
195 ),
196 ScriptErrorKind::DeclarationExpected {
197 word,
198 expected,
199 } => write!(
200 f,
201 "found '{}' at line {} position {} while a declaration is expected; {} are admitted",
202 word.text,
203 word.position.line_number,
204 word.position.line_position,
205 expected
206 .iter()
207 .map(|s| format!("'{s}'"))
208 .collect::<Vec<_>>()
209 .join(", ")
210 ),
211 ScriptErrorKind::InvalidRoot { text, root } => write!(f, "at line {} position {} '{root}' is not a valid root", text.position.line_number, text.position.line_position),
212 ScriptErrorKind::AlreadyUsedName { text } => write!(f, "at line {} position {} '{}' is already used as name", text.position.line_number, text.position.line_position, text.string),
213 ScriptErrorKind::InvalidType { text } => write!(f, "at line {} position {} '{}' is not a valid type", text.position.line_number, text.position.line_position, text.string),
214 ScriptErrorKind::InvalidStructure { text } => write!(f, "at line {} position {} '{}' is not a valid structure", text.position.line_number, text.position.line_position, text.string),
215 ScriptErrorKind::UnimportedElement { text } => write!(f, "at line {} position {} element '{}' is not imported nor locally available", text.position.line_number, text.position.line_position, text.string),
216 ScriptErrorKind::AlreadyDeclared { text } => write!(f, "at line {} position {} '{}' is already declared", text.position.line_number, text.position.line_position, text.string),
217 ScriptErrorKind::AlreadyAssigned { text } => write!(f, "at line {} position {} '{}' is already assigned", text.position.line_number, text.position.line_position, text.string),
218 ScriptErrorKind::MissingType { text } => write!(f, "at line {} position {} type for '{}' is missing", text.position.line_number, text.position.line_position, text.string),
219 ScriptErrorKind::MissingValue { text } => write!(f, "at line {} position {} value for '{}' is missing", text.position.line_number, text.position.line_position, text.string),
220 ScriptErrorKind::DefaultForbidden { text } => write!(f, "at line {} position {} '{}' cannot have default value", text.position.line_number, text.position.line_position, text.string),
221 ScriptErrorKind::DefaultForbiddenForGenerics { text , generic} => write!(f, "at line {} position {} '{}' cannot have default value because '{}' is treated as generic", text.position.line_number, text.position.line_position, text.string, generic),
222 ScriptErrorKind::ConstDeclarationOnly { text } => write!(f, "at line {} position {} '{}' cannot be otherwise than 'const'", text.position.line_number, text.position.line_position, text.string),
223 ScriptErrorKind::FlowForbidden { text } => write!(f, "at line {} position {} '{}' cannot have flow specification", text.position.line_number, text.position.line_position, text.string),
224 ScriptErrorKind::StructureForbidden { text } => write!(f, "at line {} position {} '{}' cannot have structure specification", text.position.line_number, text.position.line_position, text.string),
225 ScriptErrorKind::TypeForbidden { text } => write!(f, "at line {} position {} '{}' cannot have type specification", text.position.line_number, text.position.line_position, text.string),
226 ScriptErrorKind::ConnectionMustTransmit { from, to } => write!(f, "at line {} position {}, connection from '{}' to '{}' must transmit data", from.position.line_number, from.position.line_position, from.string, to.string),
227 ScriptErrorKind::TreatmentNotFound { text } => write!(f, "at line {} position {} cannot find treatment '{}'", text.position.line_number, text.position.line_position, text.string),
228 ScriptErrorKind::NameRequired { text } => write!(f, "at line {} position {} a name is required for assignation to '{}'", text.position.line_number, text.position.line_position, text.string),
229 ScriptErrorKind::UndeclaredModel { text } => write!(f, "at line {} position {} no model declared as '{}'", text.position.line_number, text.position.line_position, text.string),
230 ScriptErrorKind::UndeclaredParameter { text } => write!(f, "at line {} position {} no parameter declared as '{}'", text.position.line_number, text.position.line_position, text.string),
231 ScriptErrorKind::UndeclaredContext { text } => write!(f, "at line {} position {} no context declared as '{}'", text.position.line_number, text.position.line_position, text.string),
232 ScriptErrorKind::UndeclaredData { text } => write!(f, "at line {} position {} no data type declared as '{}'", text.position.line_number, text.position.line_position, text.string),
233 ScriptErrorKind::ReferenceUnset { debug_reference } => write!(f, "reference is not set, this is an internal error: '{debug_reference}'"),
234 ScriptErrorKind::InvalidBoolean { text } => write!(f, "at line {} position {} '{}' is not a boolean value", text.position.line_number, text.position.line_position, text.string),
235 ScriptErrorKind::InvalidNumber { text } => write!(f, "at line {} position {} '{}' is not a numeric value", text.position.line_number, text.position.line_position, text.string),
236 ScriptErrorKind::InvalidString { text } => write!(f, "at line {} position {} '{}' is not a correctly formatted string", text.position.line_number, text.position.line_position, text.string),
237 ScriptErrorKind::InvalidCharacter { text } => write!(f, "at line {} position {} '{}' is not a valid character", text.position.line_number, text.position.line_position, text.string),
238 ScriptErrorKind::InvalidByte { text } => write!(f, "at line {} position {} '{}' is not a valid byte", text.position.line_number, text.position.line_position, text.string),
239 ScriptErrorKind::ExecutiveRestitutionFailed { text, message } => write!(f, "at line {} position {} error occured with value '{}' because: {}", text.position.line_number, text.position.line_position, text.string, message),
240 ScriptErrorKind::MissingFunctionParameter { text, index } => write!(f, "at line {} position {} for function '{}' parameter is missing at position {index}", text.position.line_number, text.position.line_position, text.string),
241 ScriptErrorKind::MissingFunctionGeneric { text, index } => write!(f, "at line {} position {} for function '{}' generic is missing at position {index}", text.position.line_number, text.position.line_position, text.string),
242 ScriptErrorKind::MissingTreatmentGeneric { text } => write!(f, "at line {} position {} for treatment '{}' generic is missing", text.position.line_number, text.position.line_position, text.string),
243 ScriptErrorKind::InvalidGeneric { text } => write!(f, "at line {} position {} '{}' is not a valid generic name", text.position.line_number, text.position.line_position, text.string),
244 ScriptErrorKind::InvalidTrait { text } => write!(f, "at line {} position {} '{}' is not a valid trait", text.position.line_number, text.position.line_position, text.string),
245 ScriptErrorKind::UnexistingDependency { text, root } => write!(f, "at line {} position {} '{root}' is not a dependency", text.position.line_number, text.position.line_position),
246 ScriptErrorKind::Logic { error } => {
247 if let Some(ps) = error
248 .design_reference
249 .as_ref().and_then(|ptr| Arc::clone(ptr).downcast_arc::<PositionnedString>().ok())
250 {
251 write!(
252 f,
253 "at line {} position {} '{}': {}",
254 ps.position.line_number, ps.position.line_position, ps.string, error
255 )
256 } else {
257 write!(f, "{}", error)
258 }
259 }
260 ScriptErrorKind::NoDescriptor { name } => write!(
261 f,
262 "no descriptor available for '{}' line {} position {}, this is an internal error",
263 name.string, name.position.line_number, name.position.line_position
264 ),
265 }
266 }
267}
268
269impl ScriptError {
270 pub fn word(id: u32, word: Word, expected: &'static [Kind]) -> Self {
275 Self {
276 id,
277 kind: ScriptErrorKind::Word { word, expected },
278 }
279 }
280
281 pub fn end_of_script(id: u32) -> Self {
285 Self {
286 id,
287 kind: ScriptErrorKind::EndOfScript,
288 }
289 }
290
291 pub fn description_element_expected(
292 id: u32,
293 word: Word,
294 element: Word,
295 expected: &'static [&'static str],
296 ) -> Self {
297 Self {
298 id,
299 kind: ScriptErrorKind::DescriptionElementExpected {
300 word,
301 element,
302 expected,
303 },
304 }
305 }
306
307 pub fn declaration_expected(id: u32, word: Word, expected: &'static [&'static str]) -> Self {
308 Self {
309 id,
310 kind: ScriptErrorKind::DeclarationExpected { word, expected },
311 }
312 }
313
314 pub fn invalid_root(id: u32, text: PositionnedString, root: String) -> Self {
315 Self {
316 id,
317 kind: ScriptErrorKind::InvalidRoot { text, root },
318 }
319 }
320
321 pub fn already_used_name(id: u32, text: PositionnedString) -> Self {
322 Self {
323 id,
324 kind: ScriptErrorKind::AlreadyUsedName { text },
325 }
326 }
327
328 pub fn invalid_type(id: u32, text: PositionnedString) -> Self {
329 Self {
330 id,
331 kind: ScriptErrorKind::InvalidType { text },
332 }
333 }
334
335 pub fn invalid_structure(id: u32, text: PositionnedString) -> Self {
336 Self {
337 id,
338 kind: ScriptErrorKind::InvalidStructure { text },
339 }
340 }
341
342 pub fn unimported_element(id: u32, text: PositionnedString) -> Self {
343 Self {
344 id,
345 kind: ScriptErrorKind::UnimportedElement { text },
346 }
347 }
348
349 pub fn already_declared(id: u32, text: PositionnedString) -> Self {
350 Self {
351 id,
352 kind: ScriptErrorKind::AlreadyDeclared { text },
353 }
354 }
355
356 pub fn already_assigned(id: u32, text: PositionnedString) -> Self {
357 Self {
358 id,
359 kind: ScriptErrorKind::AlreadyAssigned { text },
360 }
361 }
362
363 pub fn missing_type(id: u32, text: PositionnedString) -> Self {
364 Self {
365 id,
366 kind: ScriptErrorKind::MissingType { text },
367 }
368 }
369
370 pub fn missing_value(id: u32, text: PositionnedString) -> Self {
371 Self {
372 id,
373 kind: ScriptErrorKind::MissingValue { text },
374 }
375 }
376
377 pub fn default_forbidden(id: u32, text: PositionnedString) -> Self {
378 Self {
379 id,
380 kind: ScriptErrorKind::DefaultForbidden { text },
381 }
382 }
383
384 pub fn default_forbidden_for_generics(
385 id: u32,
386 text: PositionnedString,
387 generic: String,
388 ) -> Self {
389 Self {
390 id,
391 kind: ScriptErrorKind::DefaultForbiddenForGenerics { text, generic },
392 }
393 }
394
395 pub fn const_declaration_only(id: u32, text: PositionnedString) -> Self {
396 Self {
397 id,
398 kind: ScriptErrorKind::ConstDeclarationOnly { text },
399 }
400 }
401
402 pub fn flow_forbidden(id: u32, text: PositionnedString) -> Self {
403 Self {
404 id,
405 kind: ScriptErrorKind::FlowForbidden { text },
406 }
407 }
408
409 pub fn structure_forbidden(id: u32, text: PositionnedString) -> Self {
410 Self {
411 id,
412 kind: ScriptErrorKind::StructureForbidden { text },
413 }
414 }
415
416 pub fn type_forbidden(id: u32, text: PositionnedString) -> Self {
417 Self {
418 id,
419 kind: ScriptErrorKind::TypeForbidden { text },
420 }
421 }
422
423 pub fn connection_must_transmit_data(
424 id: u32,
425 from: PositionnedString,
426 to: PositionnedString,
427 ) -> Self {
428 Self {
429 id,
430 kind: ScriptErrorKind::ConnectionMustTransmit { from, to },
431 }
432 }
433
434 pub fn treatment_not_found(id: u32, text: PositionnedString) -> Self {
435 Self {
436 id,
437 kind: ScriptErrorKind::TreatmentNotFound { text },
438 }
439 }
440
441 pub fn name_required(id: u32, text: PositionnedString) -> Self {
442 Self {
443 id,
444 kind: ScriptErrorKind::NameRequired { text },
445 }
446 }
447
448 pub fn undeclared_model(id: u32, text: PositionnedString) -> Self {
449 Self {
450 id,
451 kind: ScriptErrorKind::UndeclaredModel { text },
452 }
453 }
454
455 pub fn undeclared_parameter(id: u32, text: PositionnedString) -> Self {
456 Self {
457 id,
458 kind: ScriptErrorKind::UndeclaredParameter { text },
459 }
460 }
461
462 pub fn undeclared_context(id: u32, text: PositionnedString) -> Self {
463 Self {
464 id,
465 kind: ScriptErrorKind::UndeclaredContext { text },
466 }
467 }
468
469 pub fn undeclared_data(id: u32, text: PositionnedString) -> Self {
470 Self {
471 id,
472 kind: ScriptErrorKind::UndeclaredData { text },
473 }
474 }
475
476 pub fn reference_unset(id: u32, debug_reference: String) -> Self {
477 Self {
478 id,
479 kind: ScriptErrorKind::ReferenceUnset { debug_reference },
480 }
481 }
482
483 pub fn invalid_boolean(id: u32, text: PositionnedString) -> Self {
484 Self {
485 id,
486 kind: ScriptErrorKind::InvalidBoolean { text },
487 }
488 }
489
490 pub fn invalid_number(id: u32, text: PositionnedString) -> Self {
491 Self {
492 id,
493 kind: ScriptErrorKind::InvalidNumber { text },
494 }
495 }
496
497 pub fn invalid_string(id: u32, text: PositionnedString) -> Self {
498 Self {
499 id,
500 kind: ScriptErrorKind::InvalidString { text },
501 }
502 }
503
504 pub fn invalid_character(id: u32, text: PositionnedString) -> Self {
505 Self {
506 id,
507 kind: ScriptErrorKind::InvalidCharacter { text },
508 }
509 }
510
511 pub fn invalid_byte(id: u32, text: PositionnedString) -> Self {
512 Self {
513 id,
514 kind: ScriptErrorKind::InvalidByte { text },
515 }
516 }
517
518 pub fn executive_restitution_failed(id: u32, text: PositionnedString, message: String) -> Self {
519 Self {
520 id,
521 kind: ScriptErrorKind::ExecutiveRestitutionFailed { text, message },
522 }
523 }
524
525 pub fn missing_function_parameter(id: u32, text: PositionnedString, index: usize) -> Self {
526 Self {
527 id,
528 kind: ScriptErrorKind::MissingFunctionParameter { text, index },
529 }
530 }
531
532 pub fn missing_function_generic(id: u32, text: PositionnedString, index: usize) -> Self {
533 Self {
534 id,
535 kind: ScriptErrorKind::MissingFunctionGeneric { text, index },
536 }
537 }
538
539 pub fn missing_treatment_generic(id: u32, text: PositionnedString) -> Self {
540 Self {
541 id,
542 kind: ScriptErrorKind::MissingTreatmentGeneric { text },
543 }
544 }
545
546 pub fn invalid_generic(id: u32, text: PositionnedString) -> Self {
547 Self {
548 id,
549 kind: ScriptErrorKind::InvalidGeneric { text },
550 }
551 }
552
553 pub fn invalid_trait(id: u32, text: PositionnedString) -> Self {
554 Self {
555 id,
556 kind: ScriptErrorKind::InvalidTrait { text },
557 }
558 }
559
560 pub fn unexisting_dependency(id: u32, text: PositionnedString, root: String) -> Self {
561 Self {
562 id,
563 kind: ScriptErrorKind::UnexistingDependency { text, root },
564 }
565 }
566
567 pub fn logic(id: u32, error: LogicError) -> Self {
568 Self {
569 id,
570 kind: ScriptErrorKind::Logic { error },
571 }
572 }
573
574 pub fn no_descriptor(id: u32, name: PositionnedString) -> Self {
575 Self {
576 id,
577 kind: ScriptErrorKind::NoDescriptor { name },
578 }
579 }
580}
581
582impl Display for ScriptError {
583 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
584 write!(f, "S{:04}: {}", self.id, self.kind)
585 }
586}
587
588impl From<LogicError> for ScriptError {
589 fn from(le: LogicError) -> Self {
590 ScriptError::logic(0, le)
591 }
592}
593
594impl Error for ScriptError {
595 fn source(&self) -> Option<&(dyn Error + 'static)> {
596 None
598 }
599}
600
601pub type ScriptErrors = Vec<ScriptError>;
602pub type ScriptResult<T> = Status<T, ScriptError, ScriptError>;
603
604impl From<ScriptError> for ScriptErrors {
605 fn from(value: ScriptError) -> Self {
606 vec![value]
607 }
608}