nginx_lint_parser/
error.rs1use crate::ast::Position;
12use std::fmt;
13use thiserror::Error;
14
15#[derive(Debug, Clone, Error)]
17pub enum LexerError {
18 #[error("Unterminated string starting at line {}, column {}", .position.line, .position.column)]
20 UnterminatedString { position: Position },
21
22 #[error("Invalid escape sequence '\\{ch}' at line {}, column {}", .position.line, .position.column)]
24 InvalidEscapeSequence { ch: char, position: Position },
25
26 #[error("Unexpected character '{ch}' at line {}, column {}", .position.line, .position.column)]
28 UnexpectedChar { ch: char, position: Position },
29}
30
31impl LexerError {
32 pub fn position(&self) -> Position {
34 match self {
35 LexerError::UnterminatedString { position } => *position,
36 LexerError::InvalidEscapeSequence { position, .. } => *position,
37 LexerError::UnexpectedChar { position, .. } => *position,
38 }
39 }
40}
41
42#[derive(Debug, Clone, Error)]
46pub enum ParseError {
47 #[error("{0}")]
49 Lexer(#[from] LexerError),
50
51 #[error("Expected '{expected}' but found '{found}' at line {}, column {}", .position.line, .position.column)]
53 UnexpectedToken {
54 expected: String,
55 found: String,
56 position: Position,
57 },
58
59 #[error("Unexpected end of file at line {}, column {}", .position.line, .position.column)]
61 UnexpectedEof { position: Position },
62
63 #[error("Expected directive name at line {}, column {}", .position.line, .position.column)]
65 ExpectedDirectiveName { position: Position },
66
67 #[error("Missing semicolon at line {}, column {}", .position.line, .position.column)]
69 MissingSemicolon { position: Position },
70
71 #[error("Unmatched closing brace at line {}, column {}", .position.line, .position.column)]
73 UnmatchedCloseBrace { position: Position },
74
75 #[error("Unclosed block starting at line {}, column {}", .position.line, .position.column)]
77 UnclosedBlock { position: Position },
78
79 #[error("Failed to read file: {0}")]
81 IoError(String),
82}
83
84impl ParseError {
85 pub fn position(&self) -> Option<Position> {
90 match self {
91 ParseError::Lexer(e) => Some(e.position()),
92 ParseError::UnexpectedToken { position, .. } => Some(*position),
93 ParseError::UnexpectedEof { position } => Some(*position),
94 ParseError::ExpectedDirectiveName { position } => Some(*position),
95 ParseError::MissingSemicolon { position } => Some(*position),
96 ParseError::UnmatchedCloseBrace { position } => Some(*position),
97 ParseError::UnclosedBlock { position } => Some(*position),
98 ParseError::IoError(_) => None,
99 }
100 }
101}
102
103pub type ParseResult<T> = Result<T, ParseError>;
105
106impl fmt::Display for Position {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 write!(f, "{}:{}", self.line, self.column)
110 }
111}