1use crate::{
4 reporting::{Diagnostic, Highlight},
5 source_tracking::fragment::Fragment,
6};
7use std::borrow::Cow;
8
9#[allow(missing_docs)]
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub enum ParserErrorKind {
15 EncounteredUnknownToken,
16 EncounteredUnterminatedComment,
17 EncounteredUnterminatedString,
18 ExpectedAtomicTypeSignature,
19 ExpectedBooleanLiteral,
20 ExpectedIdentifier,
21 ExpectedImportDeclaration,
22 ExpectedIntegerLiteral,
23 ExpectedPath,
24 ExpectedReferenceTypeSignature,
25 ExpectedTypeSignature,
26 ExpectedWhitespace,
27 ImportMustEndWithSemicolon,
28 UnterminatedGenericTypeSignature,
29}
30
31impl ParserErrorKind {
32 pub const fn describe(self) -> &'static str {
34 use ParserErrorKind::*;
35
36 match self {
37 EncounteredUnknownToken => "encountered unknown token",
38 EncounteredUnterminatedComment => {
39 "encountered unterminated multiline comment while parsing"
40 }
41 EncounteredUnterminatedString => {
42 "encountered unterminated string literal while parsing"
43 }
44 ExpectedAtomicTypeSignature => "expected atomic primitive type",
45 ExpectedBooleanLiteral => "expected boolean literal",
46 ExpectedIdentifier => "expected identifier",
47 ExpectedImportDeclaration => "expected import declaration",
48 ExpectedIntegerLiteral => "expected integer literal",
49 ExpectedPath => "expected path or identifier",
50 ExpectedReferenceTypeSignature => "expected reference type signature",
51 ExpectedTypeSignature => "expected type signature",
52 ExpectedWhitespace => "expected whitespace character(s)",
53 ImportMustEndWithSemicolon => "import declarations must end with a semicolon",
54 UnterminatedGenericTypeSignature => "generic type signature must end with a `>`",
55 }
56 }
57
58 pub const fn at(self, f: Fragment) -> ParserError {
60 ParserError {
61 kind: self,
62 location: f,
63 help: Vec::new(),
64 }
65 }
66}
67
68#[derive(Debug)]
72pub struct ParserError {
73 pub kind: ParserErrorKind,
75
76 pub location: Fragment,
78
79 pub help: Vec<Cow<'static, str>>,
81}
82
83impl ParserError {
84 pub fn with_help(mut self, help: impl Into<Cow<'static, str>>) -> Self {
86 self.help.push(help.into());
87 self
88 }
89
90 pub fn as_diagnostic(self) -> Diagnostic {
92 let description = self.kind.describe();
93
94 let message = if self.location.is_empty_at_end_of_source() {
96 Cow::Borrowed("found end of source here")
97 } else {
98 Cow::Borrowed("")
99 };
100
101 let mut diagnostic = Diagnostic::error()
102 .with_message(description)
103 .with_highlights([Highlight::primary(self.location.clone(), message)]);
104
105 if !self.help.is_empty() {
106 diagnostic = diagnostic.with_notes(self.help);
107 }
108
109 diagnostic
110 }
111}