1use std::fmt;
4use std::num::TryFromIntError;
5use std::sync::Arc;
6
7use super::{RList, RValue, Vector};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum ConditionKind {
12 Error,
13 Warning,
14 Message,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum RErrorKind {
20 Type,
21 Argument,
22 Name,
23 Index,
24 Parse,
25 Interrupt,
26 Other,
27}
28
29#[derive(Debug, Clone)]
35pub enum RError {
36 Standard {
38 kind: RErrorKind,
39 message: String,
40 #[allow(dead_code)]
41 source: Option<Arc<dyn std::error::Error + Send + Sync>>,
42 },
43 Condition {
47 condition: RValue,
48 kind: ConditionKind,
49 },
50}
51
52#[derive(Debug, Clone)]
54pub enum RSignal {
55 Return(RValue),
56 Break,
57 Next,
58}
59
60#[derive(Debug, Clone)]
63pub enum RFlow {
64 Error(RError),
65 Signal(RSignal),
66}
67
68impl RError {
71 pub fn new(kind: RErrorKind, message: impl Into<String>) -> Self {
73 RError::Standard {
74 kind,
75 message: message.into(),
76 source: None,
77 }
78 }
79
80 pub fn from_source(
82 kind: RErrorKind,
83 source: impl std::error::Error + Send + Sync + 'static,
84 ) -> Self {
85 let message = format!("{}", source);
86 RError::Standard {
87 kind,
88 message,
89 source: Some(Arc::new(source)),
90 }
91 }
92
93 pub fn other(message: impl Into<String>) -> Self {
95 RError::new(RErrorKind::Other, message)
96 }
97
98 pub fn interrupt() -> Self {
100 RError::new(RErrorKind::Interrupt, "Ctrl+C: computation interrupted")
101 }
102
103 pub fn is_interrupt(&self) -> bool {
105 matches!(
106 self,
107 RError::Standard {
108 kind: RErrorKind::Interrupt,
109 ..
110 }
111 )
112 }
113
114 #[allow(dead_code)]
116 pub fn kind(&self) -> Option<RErrorKind> {
117 match self {
118 RError::Standard { kind, .. } => Some(*kind),
119 RError::Condition { .. } => None,
120 }
121 }
122
123 #[allow(dead_code)]
125 pub fn message(&self) -> String {
126 match self {
127 RError::Standard { message, .. } => message.clone(),
128 RError::Condition { condition, .. } => {
129 if let RValue::List(list) = condition {
130 for (name, val) in &list.values {
131 if name.as_deref() == Some("message") {
132 if let RValue::Vector(rv) = val {
133 if let Some(s) = rv.as_character_scalar() {
134 return s;
135 }
136 }
137 }
138 }
139 }
140 format!("{}", self)
141 }
142 }
143 }
144
145 #[allow(dead_code)]
147 pub fn source(&self) -> Option<&(dyn std::error::Error + Send + Sync)> {
148 match self {
149 RError::Standard { source, .. } => source.as_deref(),
150 RError::Condition { .. } => None,
151 }
152 }
153}
154
155impl fmt::Display for RError {
156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157 match self {
158 RError::Standard { kind, message, .. } => {
159 let prefix = match kind {
160 RErrorKind::Type => "Error",
161 RErrorKind::Argument => "Error in argument",
162 RErrorKind::Name => "Error",
163 RErrorKind::Index => "Error in indexing",
164 RErrorKind::Parse => "Error in parse",
165 RErrorKind::Interrupt => return write!(f, "Interrupted"),
166 RErrorKind::Other => "Error",
167 };
168 if *kind == RErrorKind::Name {
170 write!(f, "Error: object '{}' not found", message)
171 } else {
172 write!(f, "{}: {}", prefix, message)
173 }
174 }
175 RError::Condition { condition, .. } => {
176 if let RValue::List(list) = condition {
177 for (name, val) in &list.values {
178 if name.as_deref() == Some("message") {
179 if let RValue::Vector(rv) = val {
180 if let Some(s) = rv.as_character_scalar() {
181 return write!(f, "Error: {}", s);
182 }
183 }
184 }
185 }
186 }
187 write!(f, "Error: <condition>")
188 }
189 }
190 }
191}
192
193impl From<RError> for RFlow {
198 fn from(e: RError) -> Self {
199 RFlow::Error(e)
200 }
201}
202
203impl From<RSignal> for RFlow {
204 fn from(s: RSignal) -> Self {
205 RFlow::Signal(s)
206 }
207}
208
209impl From<RFlow> for RError {
210 fn from(f: RFlow) -> Self {
213 match f {
214 RFlow::Error(e) => e,
215 RFlow::Signal(s) => RError::other(format!("{}", s)),
216 }
217 }
218}
219
220impl From<TryFromIntError> for RFlow {
221 fn from(e: TryFromIntError) -> Self {
222 RFlow::Error(RError::from_source(RErrorKind::Type, e))
223 }
224}
225
226impl From<TryFromIntError> for RError {
227 fn from(e: TryFromIntError) -> Self {
228 RError::from_source(RErrorKind::Type, e)
229 }
230}
231
232impl fmt::Display for RFlow {
233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 match self {
235 RFlow::Error(e) => write!(f, "{}", e),
236 RFlow::Signal(s) => write!(f, "{}", s),
237 }
238 }
239}
240
241impl fmt::Display for RSignal {
242 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243 match self {
244 RSignal::Return(_) => write!(f, "no function to return from"),
245 RSignal::Break => write!(f, "no loop for break/next, jumping to top level"),
246 RSignal::Next => write!(f, "no loop for break/next, jumping to top level"),
247 }
248 }
249}
250
251pub fn make_condition(message: &str, classes: &[&str]) -> RValue {
257 let mut list = RList::new(vec![
258 (
259 Some("message".to_string()),
260 RValue::vec(Vector::Character(vec![Some(message.to_string())].into())),
261 ),
262 (Some("call".to_string()), RValue::Null),
263 ]);
264 let class_vec: Vec<Option<String>> = classes.iter().map(|s| Some(s.to_string())).collect();
265 list.set_attr(
266 "class".to_string(),
267 RValue::vec(Vector::Character(class_vec.into())),
268 );
269 RValue::List(list)
270}
271
272pub fn make_condition_with_call(message: &str, call: RValue, classes: &[&str]) -> RValue {
274 let mut list = RList::new(vec![
275 (
276 Some("message".to_string()),
277 RValue::vec(Vector::Character(vec![Some(message.to_string())].into())),
278 ),
279 (Some("call".to_string()), call),
280 ]);
281 let class_vec: Vec<Option<String>> = classes.iter().map(|s| Some(s.to_string())).collect();
282 list.set_attr(
283 "class".to_string(),
284 RValue::vec(Vector::Character(class_vec.into())),
285 );
286 RValue::List(list)
287}
288
289pub fn get_class(val: &RValue) -> Vec<String> {
291 let attrs = match val {
292 RValue::Vector(rv) => rv.attrs.as_ref(),
293 RValue::List(list) => list.attrs.as_ref(),
294 RValue::Language(lang) => lang.attrs.as_ref(),
295 _ => None,
296 };
297 match attrs.and_then(|a| a.get("class")) {
298 Some(RValue::Vector(rv)) => match &rv.inner {
299 Vector::Character(v) => v.iter().filter_map(|s| s.clone()).collect(),
300 _ => vec![],
301 },
302 _ => vec![],
303 }
304}
305
306