1use serde::{Deserialize, Serialize};
4use thiserror::Error;
5
6pub type Result<T> = std::result::Result<T, Error>;
8
9#[derive(Debug, Error)]
11pub enum Error {
12 #[error("Tokenization error at line {line}, column {column}: {message}")]
14 Tokenize {
15 message: String,
16 line: usize,
17 column: usize,
18 },
19
20 #[error("Parse error: {0}")]
22 Parse(String),
23
24 #[error("Generation error: {0}")]
26 Generate(String),
27
28 #[error("Unsupported: {feature} is not supported in {dialect}")]
30 Unsupported {
31 feature: String,
32 dialect: String,
33 },
34
35 #[error("Syntax error at line {line}, column {column}: {message}")]
37 Syntax {
38 message: String,
39 line: usize,
40 column: usize,
41 },
42
43 #[error("Internal error: {0}")]
45 Internal(String),
46}
47
48impl Error {
49 pub fn tokenize(message: impl Into<String>, line: usize, column: usize) -> Self {
51 Error::Tokenize {
52 message: message.into(),
53 line,
54 column,
55 }
56 }
57
58 pub fn parse(message: impl Into<String>) -> Self {
60 Error::Parse(message.into())
61 }
62
63 pub fn generate(message: impl Into<String>) -> Self {
65 Error::Generate(message.into())
66 }
67
68 pub fn unsupported(feature: impl Into<String>, dialect: impl Into<String>) -> Self {
70 Error::Unsupported {
71 feature: feature.into(),
72 dialect: dialect.into(),
73 }
74 }
75
76 pub fn syntax(message: impl Into<String>, line: usize, column: usize) -> Self {
78 Error::Syntax {
79 message: message.into(),
80 line,
81 column,
82 }
83 }
84
85 pub fn internal(message: impl Into<String>) -> Self {
87 Error::Internal(message.into())
88 }
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
93#[serde(rename_all = "lowercase")]
94pub enum ValidationSeverity {
95 Error,
97 Warning,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct ValidationError {
104 pub message: String,
106 pub line: Option<usize>,
108 pub column: Option<usize>,
110 pub severity: ValidationSeverity,
112 pub code: String,
114}
115
116impl ValidationError {
117 pub fn error(message: impl Into<String>, code: impl Into<String>) -> Self {
119 Self {
120 message: message.into(),
121 line: None,
122 column: None,
123 severity: ValidationSeverity::Error,
124 code: code.into(),
125 }
126 }
127
128 pub fn warning(message: impl Into<String>, code: impl Into<String>) -> Self {
130 Self {
131 message: message.into(),
132 line: None,
133 column: None,
134 severity: ValidationSeverity::Warning,
135 code: code.into(),
136 }
137 }
138
139 pub fn with_line(mut self, line: usize) -> Self {
141 self.line = Some(line);
142 self
143 }
144
145 pub fn with_column(mut self, column: usize) -> Self {
147 self.column = Some(column);
148 self
149 }
150
151 pub fn with_location(mut self, line: usize, column: usize) -> Self {
153 self.line = Some(line);
154 self.column = Some(column);
155 self
156 }
157}
158
159#[derive(Debug, Serialize, Deserialize)]
161pub struct ValidationResult {
162 pub valid: bool,
164 pub errors: Vec<ValidationError>,
166}
167
168impl ValidationResult {
169 pub fn success() -> Self {
171 Self {
172 valid: true,
173 errors: Vec::new(),
174 }
175 }
176
177 pub fn with_errors(errors: Vec<ValidationError>) -> Self {
179 let has_errors = errors.iter().any(|e| e.severity == ValidationSeverity::Error);
180 Self {
181 valid: !has_errors,
182 errors,
183 }
184 }
185
186 pub fn add_error(&mut self, error: ValidationError) {
188 if error.severity == ValidationSeverity::Error {
189 self.valid = false;
190 }
191 self.errors.push(error);
192 }
193}