potenv/tokenizer/
err.rs

1use std::path::{Path, PathBuf};
2
3use thiserror::Error;
4
5use super::pos::Position;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum ErrorKind {
9    Eof,
10    NullCharacter,
11    UnescapedSpecialCharacter(char),
12    UnterminatedSingleQuotedString,
13    UnterminatedDoubleQuotedString,
14    UnsupportedShellParameter(String),
15    UnterminatedExpansion,
16    UnsupportedCommandExpansion,
17    UnsupportedCommandOrArithmeticExpansion,
18    InvalidCharacter(char),
19}
20
21impl std::fmt::Display for ErrorKind {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        match self {
24            Self::Eof => write!(f, "Unexpected end of input"),
25            Self::NullCharacter => write!(f, "Unexpected <NUL> character"),
26            Self::UnescapedSpecialCharacter(ch) => {
27                write!(f, "Unescaped special shell character '{ch}'")
28            }
29            Self::UnterminatedSingleQuotedString => {
30                write!(f, "Unterminated single-quoted string")
31            }
32            Self::UnterminatedDoubleQuotedString => {
33                write!(f, "Unterminated double-quoted string")
34            }
35            Self::UnsupportedShellParameter(p) => {
36                write!(f, "Unsupported special shell parameter: {p}")
37            }
38            Self::UnterminatedExpansion => write!(f, "Unterminated expansion"),
39            Self::UnsupportedCommandExpansion => write!(f, "Unsupported command expansion"),
40            Self::UnsupportedCommandOrArithmeticExpansion => {
41                write!(f, "Unsupported command or arithmetic expansion")
42            }
43            Self::InvalidCharacter(ch) => write!(f, "Invalid character '{ch}'"),
44        }
45    }
46}
47
48#[derive(Error, Debug, PartialEq, Eq)]
49pub struct SyntaxError {
50    kind: ErrorKind,
51    position: Position,
52    filename: Option<PathBuf>,
53}
54
55impl std::fmt::Display for SyntaxError {
56    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        self.kind().fmt(f)?;
58        if let Some(file) = self.file() {
59            write!(f, " in {}", file.display())?;
60        }
61        write!(f, " on line {}, column {}", self.line(), self.column())
62    }
63}
64
65impl SyntaxError {
66    pub fn new(kind: ErrorKind, position: Position, filename: Option<PathBuf>) -> Self {
67        Self {
68            kind,
69            position,
70            filename,
71        }
72    }
73
74    pub fn kind(&self) -> &ErrorKind {
75        &self.kind
76    }
77
78    pub fn line(&self) -> usize {
79        self.position.line
80    }
81
82    pub fn column(&self) -> usize {
83        self.position.column
84    }
85
86    pub fn file(&self) -> Option<&Path> {
87        self.filename.as_deref()
88    }
89}