ludtwig_parser/parser/
parse_error.rs1use crate::lexer::Token;
2use std::fmt;
3use std::fmt::Formatter;
4
5use crate::syntax::untyped::{SyntaxKind, TextRange};
6
7#[derive(Debug, Clone, Eq, PartialEq)]
8pub struct ParseErrorBuilder {
9 pub(super) range: Option<TextRange>,
10 pub(super) found: Option<SyntaxKind>,
11 pub(super) expected: String,
12}
13
14impl ParseErrorBuilder {
15 pub fn new<S>(expected: S) -> Self
18 where
19 S: Into<String>,
20 {
21 Self {
22 range: None,
23 found: None,
24 expected: expected.into(),
25 }
26 }
27
28 pub(crate) fn at_token(mut self, token: &Token) -> Self {
29 self.range = Some(token.range);
30 self.found = Some(token.kind);
31 self
32 }
33
34 pub(super) fn build(self) -> ParseError {
35 ParseError {
36 range: self.range.unwrap(),
37 found: self.found,
38 expected: self.expected,
39 }
40 }
41}
42
43#[derive(Debug, Clone, Eq, PartialEq)]
44pub struct ParseError {
45 pub range: TextRange,
46 pub found: Option<SyntaxKind>,
47 pub expected: String,
48}
49
50impl ParseError {
51 #[must_use]
52 pub fn expected_message(&self) -> String {
53 if let Some(found) = self.found {
54 format!("expected {} but found {}", self.expected, found)
55 } else {
56 format!("expected {} but reached end of file", self.expected)
57 }
58 }
59}
60
61impl fmt::Display for ParseError {
62 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
63 write!(
64 f,
65 "error at {}..{}: ",
66 u32::from(self.range.start()),
67 u32::from(self.range.end()),
68 )?;
69
70 write!(f, "{}", self.expected_message())
71 }
72}
73
74#[cfg(test)]
75mod test {
76 use super::*;
77 use crate::T;
78 use rowan::TextSize;
79
80 #[test]
81 fn parse_error_display() {
82 let range = TextRange::new(TextSize::from(3), TextSize::from(5));
83 let parse_error = ParseError {
84 range,
85 found: Some(T!["{%"]),
86 expected: "word".to_string(),
87 };
88
89 assert_eq!(
90 format!("{parse_error}"),
91 "error at 3..5: expected word but found {%"
92 );
93 }
94}