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 { feature: String, dialect: String },
31
32 #[error("Syntax error at line {line}, column {column}: {message}")]
34 Syntax {
35 message: String,
36 line: usize,
37 column: usize,
38 },
39
40 #[error("Internal error: {0}")]
42 Internal(String),
43}
44
45impl Error {
46 pub fn tokenize(message: impl Into<String>, line: usize, column: usize) -> Self {
48 Error::Tokenize {
49 message: message.into(),
50 line,
51 column,
52 }
53 }
54
55 pub fn parse(message: impl Into<String>) -> Self {
57 Error::Parse(message.into())
58 }
59
60 pub fn generate(message: impl Into<String>) -> Self {
62 Error::Generate(message.into())
63 }
64
65 pub fn unsupported(feature: impl Into<String>, dialect: impl Into<String>) -> Self {
67 Error::Unsupported {
68 feature: feature.into(),
69 dialect: dialect.into(),
70 }
71 }
72
73 pub fn syntax(message: impl Into<String>, line: usize, column: usize) -> Self {
75 Error::Syntax {
76 message: message.into(),
77 line,
78 column,
79 }
80 }
81
82 pub fn internal(message: impl Into<String>) -> Self {
84 Error::Internal(message.into())
85 }
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
90#[serde(rename_all = "lowercase")]
91pub enum ValidationSeverity {
92 Error,
94 Warning,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct ValidationError {
101 pub message: String,
103 pub line: Option<usize>,
105 pub column: Option<usize>,
107 pub severity: ValidationSeverity,
109 pub code: String,
111}
112
113impl ValidationError {
114 pub fn error(message: impl Into<String>, code: impl Into<String>) -> Self {
116 Self {
117 message: message.into(),
118 line: None,
119 column: None,
120 severity: ValidationSeverity::Error,
121 code: code.into(),
122 }
123 }
124
125 pub fn warning(message: impl Into<String>, code: impl Into<String>) -> Self {
127 Self {
128 message: message.into(),
129 line: None,
130 column: None,
131 severity: ValidationSeverity::Warning,
132 code: code.into(),
133 }
134 }
135
136 pub fn with_line(mut self, line: usize) -> Self {
138 self.line = Some(line);
139 self
140 }
141
142 pub fn with_column(mut self, column: usize) -> Self {
144 self.column = Some(column);
145 self
146 }
147
148 pub fn with_location(mut self, line: usize, column: usize) -> Self {
150 self.line = Some(line);
151 self.column = Some(column);
152 self
153 }
154}
155
156#[derive(Debug, Serialize, Deserialize)]
158pub struct ValidationResult {
159 pub valid: bool,
161 pub errors: Vec<ValidationError>,
163}
164
165impl ValidationResult {
166 pub fn success() -> Self {
168 Self {
169 valid: true,
170 errors: Vec::new(),
171 }
172 }
173
174 pub fn with_errors(errors: Vec<ValidationError>) -> Self {
176 let has_errors = errors
177 .iter()
178 .any(|e| e.severity == ValidationSeverity::Error);
179 Self {
180 valid: !has_errors,
181 errors,
182 }
183 }
184
185 pub fn add_error(&mut self, error: ValidationError) {
187 if error.severity == ValidationSeverity::Error {
188 self.valid = false;
189 }
190 self.errors.push(error);
191 }
192}