1use std::fmt;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct SourceLoc {
12 pub line: usize,
13 pub col: usize,
14 pub source_line: Option<String>,
16}
17
18impl SourceLoc {
19 pub fn new(line: usize, col: usize) -> Self {
20 Self {
21 line,
22 col,
23 source_line: None,
24 }
25 }
26
27 pub fn with_source(mut self, text: String) -> Self {
28 self.source_line = Some(text);
29 self
30 }
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum RexxError {
37 Halt,
39 ResourceExhausted,
41 UnmatchedComment,
43 ExpectedWhenOtherwise,
45 UnexpectedThenElse,
47 UnexpectedWhenOtherwise,
49 UnexpectedEnd,
51 InvalidCharacter,
53 IncompleteBlock,
55 InvalidHexBinary,
57 LabelNotFound,
59 UnexpectedProcedure,
61 ExpectedThen,
63 ExpectedStringOrSymbol,
65 ExpectedSymbol,
67 InvalidDataOnEnd,
69 InvalidTrace,
71 InvalidSubKeyword,
73 InvalidWholeNumber,
75 InvalidDoSyntax,
77 InvalidLeaveIterate,
79 EnvironmentNameTooLong,
81 NameTooLong,
83 InvalidName,
85 InvalidExpressionResult,
87 InvalidLogicalValue,
89 InvalidExpression,
91 UnmatchedParen,
93 UnexpectedCommaOrParen,
95 InvalidTemplate,
97 IncorrectCall,
99 BadArithmetic,
101 ArithmeticOverflow,
103 RoutineNotFound,
105 NoReturnData,
107 NoReturnValue,
109 InvalidVariableRef,
111 SystemFailure,
113 InterpretationError,
115}
116
117impl RexxError {
118 pub fn number(self) -> u32 {
120 match self {
121 Self::Halt => 4,
122 Self::ResourceExhausted => 5,
123 Self::UnmatchedComment => 6,
124 Self::ExpectedWhenOtherwise => 7,
125 Self::UnexpectedThenElse => 8,
126 Self::UnexpectedWhenOtherwise => 9,
127 Self::UnexpectedEnd => 10,
128 Self::InvalidCharacter => 13,
129 Self::IncompleteBlock => 14,
130 Self::InvalidHexBinary => 15,
131 Self::LabelNotFound => 16,
132 Self::UnexpectedProcedure => 17,
133 Self::ExpectedThen => 18,
134 Self::ExpectedStringOrSymbol => 19,
135 Self::ExpectedSymbol => 20,
136 Self::InvalidDataOnEnd => 21,
137 Self::InvalidTrace => 24,
138 Self::InvalidSubKeyword => 25,
139 Self::InvalidWholeNumber => 26,
140 Self::InvalidDoSyntax => 27,
141 Self::InvalidLeaveIterate => 28,
142 Self::EnvironmentNameTooLong => 29,
143 Self::NameTooLong => 30,
144 Self::InvalidName => 31,
145 Self::InvalidExpressionResult => 33,
146 Self::InvalidLogicalValue => 34,
147 Self::InvalidExpression => 35,
148 Self::UnmatchedParen => 36,
149 Self::UnexpectedCommaOrParen => 37,
150 Self::InvalidTemplate => 38,
151 Self::IncorrectCall => 40,
152 Self::BadArithmetic => 41,
153 Self::ArithmeticOverflow => 42,
154 Self::RoutineNotFound => 43,
155 Self::NoReturnData => 44,
156 Self::NoReturnValue => 45,
157 Self::InvalidVariableRef => 46,
158 Self::SystemFailure => 48,
159 Self::InterpretationError => 49,
160 }
161 }
162
163 pub fn message(self) -> &'static str {
165 match self {
166 Self::Halt => "Program interrupted",
167 Self::ResourceExhausted => "System resources exhausted",
168 Self::UnmatchedComment => "Unmatched /* in source",
169 Self::ExpectedWhenOtherwise => "WHEN or OTHERWISE expected",
170 Self::UnexpectedThenElse => "Unexpected THEN or ELSE",
171 Self::UnexpectedWhenOtherwise => "Unexpected WHEN or OTHERWISE",
172 Self::UnexpectedEnd => "Unexpected or unmatched END",
173 Self::InvalidCharacter => "Invalid character in program",
174 Self::IncompleteBlock => "Incomplete DO/SELECT/IF",
175 Self::InvalidHexBinary => "Invalid hexadecimal or binary string",
176 Self::LabelNotFound => "Label not found",
177 Self::UnexpectedProcedure => "Unexpected PROCEDURE",
178 Self::ExpectedThen => "THEN expected",
179 Self::ExpectedStringOrSymbol => "String or symbol expected",
180 Self::ExpectedSymbol => "Symbol expected",
181 Self::InvalidDataOnEnd => "Invalid data on end of clause",
182 Self::InvalidTrace => "Invalid TRACE request",
183 Self::InvalidSubKeyword => "Invalid sub-keyword found",
184 Self::InvalidWholeNumber => "Invalid whole number",
185 Self::InvalidDoSyntax => "Invalid DO syntax",
186 Self::InvalidLeaveIterate => "Invalid LEAVE or ITERATE",
187 Self::EnvironmentNameTooLong => "Environment name too long",
188 Self::NameTooLong => "Name or string too long",
189 Self::InvalidName => "Name starts with number or \".\"",
190 Self::InvalidExpressionResult => "Invalid expression result",
191 Self::InvalidLogicalValue => "Logical value not 0 or 1",
192 Self::InvalidExpression => "Invalid expression",
193 Self::UnmatchedParen => "Unmatched \"(\" in expression",
194 Self::UnexpectedCommaOrParen => "Unexpected \",\" or \")\"",
195 Self::InvalidTemplate => "Invalid template or pattern",
196 Self::IncorrectCall => "Incorrect call to routine",
197 Self::BadArithmetic => "Bad arithmetic conversion",
198 Self::ArithmeticOverflow => "Arithmetic overflow/underflow",
199 Self::RoutineNotFound => "Routine not found",
200 Self::NoReturnData => "Function did not return data",
201 Self::NoReturnValue => "No data specified on function RETURN",
202 Self::InvalidVariableRef => "Invalid variable reference",
203 Self::SystemFailure => "Failure in system service",
204 Self::InterpretationError => "Interpretation error",
205 }
206 }
207}
208
209#[derive(Debug, Clone)]
211pub struct RexxDiagnostic {
212 pub error: RexxError,
213 pub location: Option<SourceLoc>,
214 pub detail: Option<String>,
215}
216
217impl RexxDiagnostic {
218 pub fn new(error: RexxError) -> Self {
219 Self {
220 error,
221 location: None,
222 detail: None,
223 }
224 }
225
226 pub fn at(mut self, loc: SourceLoc) -> Self {
227 self.location = Some(loc);
228 self
229 }
230
231 pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
232 self.detail = Some(detail.into());
233 self
234 }
235}
236
237impl fmt::Display for RexxDiagnostic {
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239 write!(
240 f,
241 "Error {} — {}",
242 self.error.number(),
243 self.error.message()
244 )?;
245
246 if let Some(ref detail) = self.detail {
247 write!(f, ": {detail}")?;
248 }
249
250 if let Some(ref loc) = self.location {
251 write!(f, "\n at line {}, column {}", loc.line, loc.col)?;
252 if let Some(ref source) = loc.source_line {
253 write!(f, "\n | {source}")?;
254 write!(f, "\n | {:>width$}", "^", width = loc.col)?;
255 }
256 }
257
258 Ok(())
259 }
260}
261
262impl std::error::Error for RexxDiagnostic {}
263
264pub type RexxResult<T> = Result<T, RexxDiagnostic>;