Skip to main content

kashida/
error.rs

1//! Pattern-compilation errors.
2
3use core::fmt;
4
5/// An error while compiling pattern text.
6#[derive(Debug, Clone, PartialEq, Eq)]
7#[non_exhaustive]
8pub struct CompileError {
9    /// What went wrong.
10    pub kind: CompileErrorKind,
11    /// 1-based line number into the compiled pattern text.
12    pub line_number: usize,
13}
14
15/// What went wrong on a pattern line.
16#[derive(Debug, Clone, PartialEq, Eq)]
17#[non_exhaustive]
18pub enum CompileErrorKind {
19    /// A `[…]` length guard that is malformed or that no run can satisfy.
20    InvalidLengthGuard(String),
21    /// A `[` length guard with no closing `]`.
22    UnterminatedLengthGuard,
23    /// A `{` group set with no closing `}`.
24    UnterminatedGroupSet,
25    /// A `{}` group set with no group names.
26    EmptyGroupSet,
27    /// A group name that is not a Unicode Joining_Group long name.
28    UnknownGroupName(String),
29    /// A token after the trailing `.` run boundary.
30    TokenAfterTrailingBoundary,
31    /// A `\` in a two-digit priority not followed by a digit.
32    ExpectedDigitAfterBackslash,
33    /// A two-digit priority whose second digit is greater than its first.
34    IncreasingPriority {
35        /// The starting priority.
36        base: u8,
37        /// The end priority it drops to.
38        min: u8,
39    },
40    /// A `\` that does not follow a priority digit.
41    BackslashWithoutDigit,
42    /// A `^` not followed by `{`, `@`, or `=`.
43    CaretNotFollowed,
44    /// An `@` or `=` with no group name after it.
45    EmptyGroupName,
46    /// A pattern line with no letter tokens.
47    NoLetters,
48    /// A character that is neither pattern syntax nor a joining letter.
49    StrayCharacter(char),
50    /// Two weights (digits or `!`) in the same inter-token gap.
51    ConflictingWeights,
52    /// A weight in the gap between a token and a `.`, where no connection
53    /// exists.
54    WeightOutsideRun,
55    /// A `use` naming a set that is not built in.
56    UnknownImport(String),
57}
58
59impl fmt::Display for CompileErrorKind {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        match self {
62            CompileErrorKind::InvalidLengthGuard(body) => {
63                write!(f, "Invalid length guard “[{body}]”")
64            }
65            CompileErrorKind::UnterminatedLengthGuard => write!(f, "Unterminated length guard"),
66            CompileErrorKind::UnterminatedGroupSet => write!(f, "Unterminated “{{” group set"),
67            CompileErrorKind::EmptyGroupSet => write!(f, "Empty “{{}}” group set"),
68            CompileErrorKind::UnknownGroupName(name) => {
69                write!(f, "Unknown Unicode Joining_Group name “{name}”")
70            }
71            CompileErrorKind::TokenAfterTrailingBoundary => {
72                write!(f, "Token after a trailing “.” boundary")
73            }
74            CompileErrorKind::ExpectedDigitAfterBackslash => {
75                write!(f, "Expected a digit after “\\”")
76            }
77            CompileErrorKind::IncreasingPriority { base, min } => {
78                write!(f, "Priority must not increase ({base}\\{min})")
79            }
80            CompileErrorKind::BackslashWithoutDigit => {
81                write!(f, "“\\” must follow a priority digit")
82            }
83            CompileErrorKind::CaretNotFollowed => {
84                write!(f, "“^” must be followed by “{{”, “@”, or “=”")
85            }
86            CompileErrorKind::EmptyGroupName => write!(f, "Empty group name"),
87            CompileErrorKind::NoLetters => write!(f, "Pattern has no letters"),
88            CompileErrorKind::StrayCharacter(ch) => write!(f, "Stray character {ch:?}"),
89            CompileErrorKind::ConflictingWeights => {
90                write!(f, "Conflicting weights at one connection")
91            }
92            CompileErrorKind::WeightOutsideRun => {
93                write!(f, "Weight outside the run at a “.” boundary")
94            }
95            CompileErrorKind::UnknownImport(name) => {
96                write!(f, "Unknown pattern set “{name}”")
97            }
98        }
99    }
100}
101
102impl fmt::Display for CompileError {
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        write!(f, "line {}: {}", self.line_number, self.kind)
105    }
106}
107
108impl std::error::Error for CompileError {}