1use crate::ast::Range;
2use crate::rules;
3use serde_derive::Serialize;
4
5#[derive(Serialize, Clone, Debug, PartialEq, Eq)]
6pub struct Diagnostic {
7 pub kind: DiagnosticKind,
8 pub range: Range,
9 pub message: String,
10
11 pub context_message: Option<String>,
13
14 pub hint: Option<String>,
15 pub related_infos: Vec<RelatedInfo>,
16}
17
18#[derive(Serialize, Clone, Debug, PartialEq, Eq)]
19pub enum DiagnosticKind {
20 Error,
21 Warning,
22}
23
24#[derive(Serialize, Clone, Debug, PartialEq, Eq)]
25pub struct RelatedInfo {
26 pub range: Range,
27 pub message: String,
28}
29
30pub type ErrorRecovery<'input> =
31 lalrpop_util::ErrorRecovery<usize, rules::aidl::Token<'input>, &'static str>;
32
33pub type ParseError<'input> =
34 lalrpop_util::ParseError<usize, rules::aidl::Token<'input>, &'static str>;
35
36impl Diagnostic {
37 pub(crate) fn from_error_recovery(
38 msg: &str,
39 lookup: &line_col::LineColLookup,
40 error_recovery: ErrorRecovery,
41 ) -> Option<Diagnostic> {
42 Self::from_parse_error(lookup, error_recovery.error).map(|d| Diagnostic {
43 message: format!("{} - {}", msg, d.message),
44 ..d
45 })
46 }
47
48 pub(crate) fn from_parse_error(
49 lookup: &line_col::LineColLookup,
50 e: ParseError,
51 ) -> Option<Diagnostic> {
52 match e {
53 lalrpop_util::ParseError::InvalidToken { location } => Some(Diagnostic {
54 kind: DiagnosticKind::Error,
55 message: "Invalid token".to_owned(),
56 context_message: Some("invalid token".to_owned()),
57 range: Range::new(lookup, location, location),
58 hint: None,
59 related_infos: Vec::new(),
60 }),
61 lalrpop_util::ParseError::UnrecognizedEOF { location, expected } => Some(Diagnostic {
62 kind: DiagnosticKind::Error,
63 message: format!("Unrecognized EOF.\n{}", expected_token_str(&expected)),
64 context_message: Some("unrecognized EOF".to_owned()),
65 range: Range::new(lookup, location, location),
66 hint: None,
67 related_infos: Vec::new(),
68 }),
69 lalrpop_util::ParseError::UnrecognizedToken { token, expected } => Some(Diagnostic {
70 kind: DiagnosticKind::Error,
71 message: format!(
72 "Unrecognized token `{}`.\n{}",
73 token.1,
74 expected_token_str(&expected)
75 ),
76 context_message: Some("unrecognized token".to_owned()),
77 range: Range::new(lookup, token.0, token.2),
78 hint: None,
79 related_infos: Vec::new(),
80 }),
81 lalrpop_util::ParseError::ExtraToken { token } => Some(Diagnostic {
82 kind: DiagnosticKind::Error,
83 message: format!("Extra token `{}`", token.1,),
84 context_message: Some("extra token".to_owned()),
85 range: Range::new(lookup, token.0, token.2),
86 hint: None,
87 related_infos: Vec::new(),
88 }),
89 lalrpop_util::ParseError::User { error: _ } => None, }
91 }
92}
93
94fn expected_token_str(v: &[String]) -> String {
96 match v.len() {
97 0 => String::new(),
98 1 => format!("Expected {}", v[0]),
99 2 => format!("Expected {} or {}", v[0], v[1]),
100 _ => format!(
101 "Expected one of {} or {}",
102 v[0..v.len() - 2].join(", "),
103 v[v.len() - 1]
104 ),
105 }
106}