glass_easel_stylesheet_compiler/
error.rs

1use std::ops::Range;
2
3use serde::{Deserialize, Serialize};
4
5/// A location in source code.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7pub struct Position {
8    pub line: u32,
9    pub utf16_col: u32,
10}
11
12impl Position {
13    /// Get the line-column offsets (in UTF-16) in the source code.
14    pub fn line_col_utf16<'s>(&self) -> (usize, usize) {
15        (self.line as usize, self.utf16_col as usize)
16    }
17}
18
19/// Parsing error object.
20#[derive(Debug, Clone, PartialEq)]
21pub struct ParseError {
22    pub path: String,
23    pub kind: ParseErrorKind,
24    pub location: Range<Position>,
25}
26
27impl std::fmt::Display for ParseError {
28    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
29        write!(
30            f,
31            "style sheet parsing error at {}:{}:{}-{}:{}: {}",
32            self.path,
33            self.location.start.line + 1,
34            self.location.start.utf16_col + 1,
35            self.location.end.line + 1,
36            self.location.end.utf16_col + 1,
37            self.kind,
38        )
39    }
40}
41
42impl std::error::Error for ParseError {}
43
44impl ParseError {
45    /// The level of the error.
46    pub fn level(&self) -> ParseErrorLevel {
47        self.kind.level()
48    }
49
50    /// An error code.
51    pub fn code(&self) -> u32 {
52        self.kind.clone() as u32
53    }
54
55    /// Whether the error prevent a success compilation.
56    pub fn prevent_success(&self) -> bool {
57        self.level() >= ParseErrorLevel::Error
58    }
59}
60
61#[derive(Clone, PartialEq, Eq)]
62pub enum ParseErrorKind {
63    UnexpectedCharacter = 0x10001,
64    IllegalImportPosition,
65    HostSelectorCombination,
66}
67
68impl ParseErrorKind {
69    fn static_message(&self) -> &'static str {
70        match self {
71            Self::UnexpectedCharacter => "unexpected character",
72            Self::IllegalImportPosition => "`@import` should be placed at the start of the stylesheet (according to CSS standard)",
73            Self::HostSelectorCombination => "`:host` selector combined with other selectors are not supported",
74        }
75    }
76
77    pub fn level(&self) -> ParseErrorLevel {
78        match self {
79            Self::UnexpectedCharacter => ParseErrorLevel::Fatal,
80            Self::IllegalImportPosition => ParseErrorLevel::Note,
81            Self::HostSelectorCombination => ParseErrorLevel::Warn,
82        }
83    }
84}
85
86impl std::fmt::Debug for ParseErrorKind {
87    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
88        write!(f, "{:?}", self.static_message())
89    }
90}
91
92impl std::fmt::Display for ParseErrorKind {
93    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
94        write!(f, "{}", self.static_message())
95    }
96}
97
98#[repr(u8)]
99#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
100pub enum ParseErrorLevel {
101    /// Likely to be an mistake and should be noticed.
102    ///
103    /// The generator may generate code that contains this kind of mistakes.
104    Note = 1,
105    /// Should be a mistake but the compiler can guess a good way to generate proper code.
106    Warn,
107    /// An error that prevents a successful compilation, but can still continue to find more errors.
108    Error,
109    /// A very serious error that can cause continuous compiling issues, such as miss matched braces.
110    Fatal,
111}