1use {
2 crate::xkb::{
3 code_slice::CodeSlice,
4 compose::{
5 parser::Parser,
6 token::{Punctuation, Token},
7 },
8 diagnostic::DiagnosticKind,
9 span::{Span, SpanExt, Spanned},
10 },
11 bstr::ByteSlice,
12 debug_fn::debug_fn,
13 std::fmt::{self, Formatter},
14 thiserror::Error,
15};
16
17#[derive(Debug, Clone, Error)]
18pub(crate) enum ParserError {
19 #[error(
20 "expected {}, but encountered EOF",
21 debug_fn(|f| write_expected(f, .0.expected)),
22 )]
23 ExpectedButEof(ExpectedButEof),
24 #[error(
25 "expected {}, but found {}",
26 debug_fn(|f| write_expected(f, .0.expected)),
27 debug_fn(|f| write_actual(f, &.0.actual)),
28 )]
29 UnexpectedToken(UnexpectedToken),
30 #[error(
31 "expected end of line, but found {}",
32 debug_fn(|f| write_actual(f, .0)),
33 )]
34 ExpectedEol(ActualToken),
35 #[error(
36 "unknown keysym {}",
37 .0.as_bstr(),
38 )]
39 UnknownKeysym(CodeSlice<'static>),
40}
41
42impl ParserError {
43 pub(crate) fn diagnostic_kind(&self) -> DiagnosticKind {
44 match self {
45 ParserError::ExpectedButEof(_) => DiagnosticKind::UnexpectedEof,
46 ParserError::UnexpectedToken(_) => DiagnosticKind::UnexpectedToken,
47 ParserError::ExpectedEol(_) => DiagnosticKind::ExpectedEol,
48 ParserError::UnknownKeysym(_) => DiagnosticKind::UnknownKeysym,
49 }
50 }
51}
52
53fn write_actual(f: &mut Formatter<'_>, actual: &ActualToken) -> fmt::Result {
54 match actual {
55 ActualToken::Ident(i) => write!(f, "`{}`", i.as_bytes().as_bstr()),
56 ActualToken::String(i) => write!(f, "{:?}", i.as_bytes().as_bstr()),
57 ActualToken::Keysym(i) => write!(f, "<{}>", i.as_bytes().as_bstr()),
58 ActualToken::Token(t) => match t {
59 Token::Ident(_) => f.write_str("an identifier"),
60 Token::Punctuation(p) => write!(f, "`{}`", punctuation_string(*p)),
61 Token::String(_) => f.write_str("a string"),
62 Token::Keysym(_) => f.write_str("a keysym"),
63 },
64 }
65}
66
67fn write_expected(f: &mut Formatter<'_>, expected: &[Expected]) -> fmt::Result {
68 if let Some(e) = get_unique_expected(expected) {
69 return write_single_expected(f, e);
70 }
71 write_expected_(f, expected, true)
72}
73
74fn write_expected_(f: &mut Formatter<'_>, expected: &[Expected], or_prefix: bool) -> fmt::Result {
75 let last = expected.len() - 1;
76 for (idx, e) in expected.iter().enumerate() {
77 if idx > 0 {
78 f.write_str(", ")?;
79 }
80 if or_prefix && idx == last {
81 f.write_str("or ")?;
82 }
83 write_single_expected(f, e)?;
84 }
85 Ok(())
86}
87
88fn get_unique_expected(expected: &[Expected]) -> Option<&Expected> {
89 if expected.len() != 1 {
90 return None;
91 }
92 Some(&expected[0])
93}
94
95fn write_single_expected(f: &mut Formatter<'_>, expected: &Expected) -> fmt::Result {
96 match expected {
97 Expected::AnyIdent => f.write_str("an identifier"),
98 Expected::AnyString => f.write_str("a string"),
99 Expected::AnyModifier => f.write_str("a modifier"),
100 Expected::AnyKeysym => f.write_str("a keysym"),
101 Expected::Punctuation(p) => {
102 write!(f, "`{}`", punctuation_string(*p))
103 }
104 }
105}
106
107fn punctuation_string(p: Punctuation) -> &'static str {
108 match p {
109 Punctuation::Exclam => "!",
110 Punctuation::Tilde => "~",
111 Punctuation::Colon => ":",
112 }
113}
114
115#[derive(Debug, Clone)]
116pub(crate) struct ExpectedButEof {
117 expected: &'static [Expected],
118}
119
120#[derive(Debug, Clone)]
121pub(crate) struct UnexpectedToken {
122 expected: &'static [Expected],
123 actual: ActualToken,
124}
125
126#[derive(Debug)]
127pub(crate) enum Expected {
128 AnyIdent,
129 AnyString,
130 AnyModifier,
131 AnyKeysym,
132 Punctuation(Punctuation),
133}
134
135#[derive(Clone, Debug, PartialEq)]
136pub(crate) enum ActualToken {
137 Ident(CodeSlice<'static>),
138 String(CodeSlice<'static>),
139 Keysym(CodeSlice<'static>),
140 Token(Token),
141}
142
143impl Parser<'_, '_, '_> {
144 pub(super) fn expected_but_eof(
145 &self,
146 span: Span,
147 expected: &'static [Expected],
148 ) -> Spanned<ParserError> {
149 ParserError::ExpectedButEof(ExpectedButEof { expected }).spanned2(span)
150 }
151
152 fn token_to_actual(&self, token: Spanned<Token>) -> ActualToken {
153 match token.val {
154 Token::Ident(i) => ActualToken::Ident(self.interner.get(i).to_owned()),
155 Token::Keysym(i) => ActualToken::Keysym(self.interner.get(i).to_owned()),
156 Token::String(i) => ActualToken::String(self.interner.get(i).to_owned()),
157 _ => ActualToken::Token(token.val),
158 }
159 }
160
161 pub(super) fn expected_eol(&self, token: Spanned<Token>) -> Spanned<ParserError> {
162 let actual = self.token_to_actual(token);
163 ParserError::ExpectedEol(actual).spanned2(token.span)
164 }
165
166 pub(super) fn unexpected_token(
167 &self,
168 expected: &'static [Expected],
169 token: Spanned<Token>,
170 ) -> Spanned<ParserError> {
171 let actual = self.token_to_actual(token);
172 ParserError::UnexpectedToken(UnexpectedToken { expected, actual }).spanned2(token.span)
173 }
174
175 pub(super) fn unknown_keysym(&self, code: &CodeSlice<'_>, span: Span) -> Spanned<ParserError> {
176 ParserError::UnknownKeysym(code.to_owned()).spanned2(span)
177 }
178}
179
180pub(super) const LHS: &[Expected] = &[
181 Expected::Punctuation(punctuation![!]),
182 Expected::Punctuation(punctuation![~]),
183 Expected::Punctuation(punctuation![:]),
184 Expected::AnyKeysym,
185 Expected::AnyModifier,
186];