1#[macro_export]
2macro_rules! location {
3 () => {{
4 let location = format!(
5 "{}{}{}:{}",
6 crate::color::auto($crate::function_name!()),
7 crate::color::fore(" @ ", 220),
8 crate::color::auto($crate::filename!()),
9 crate::color::auto(line!().to_string())
10 );
11 location
12 }};
13 (begin) => {
14 $crate::tag!([crate::color::auto(format!("in function")), $crate::location!()].join(" "))
15 };
16 (end) => {
17 $crate::tag!([crate::color::auto(format!("from function")), $crate::location!()].join(" "))
18 };
19 (unexpected) => {
20 [
21 crate::color::fore(format!("<unexpected branch in function"), 160),
22 $crate::location!(),
23 crate::color::fore(format!(">"), 160),
24 ]
25 .join(" ")
26 };
27}
28#[macro_export]
29macro_rules! filename {
30 () => {{
31 let mut parts = file!()
32 .split(std::path::MAIN_SEPARATOR_STR)
33 .map(String::from)
34 .collect::<Vec<String>>();
35 let (folder, filename) = if parts.len() > 1 {
36 let last = crate::color::auto(parts.remove(parts.len() - 1));
37 let parts = parts.iter().map(|part| crate::color::auto(part)).collect::<Vec<String>>();
38 (parts, last)
39 } else {
40 (Vec::<String>::new(), crate::color::auto(parts[0].to_string()))
41 };
42 if folder.len() > 1 {
43 format!(
44 "{}{}{}",
45 crate::color::auto(filename),
46 crate::color::fore(" in ", 7),
47 folder.join(std::path::MAIN_SEPARATOR_STR)
48 )
49 } else {
50 crate::color::auto(filename)
51 }
52 }};
53}
54#[macro_export]
55macro_rules! tag {
56 ($arg:expr) => {{
57 $crate::tag!($arg, 7)
58 }};
59 (close, $arg:expr) => {{
60 $crate::tag!(close, $arg, 7)
61 }};
62 ($arg:expr, $color:literal) => {{
63 format!(
64 "{}{}{}",
65 crate::color::fore("<", $color),
66 crate::color::auto($arg),
67 crate::color::fore(">", $color),
68 )
69 }};
70 (close, $arg:expr, $color:literal) => {{
71 format!(
72 "{}{}{}",
73 crate::color::fore("</", $color),
74 $arg,
75 crate::color::fore(">", $color),
76 )
77 }};
78}
79#[macro_export]
80macro_rules! dbg {
81 ($( $arg:expr ),* $(,)? ) => {{
82 let obj = format!("{}", [$(
83 $crate::indent!(format!("{} = {:#?}", stringify!($arg), $arg)),
84 )*].iter().map(crate::color::reset).collect::<Vec<String>>().join("\n"));
85 eprintln!("{}", crate::color::reset([$crate::location!(begin), obj, $crate::location!(end)].join("\n")));
86 }};
87}
88#[macro_export]
89macro_rules! indent {
90 ($indentation:literal, $obj:expr) => {{
91 format!("{}", $obj)
92 .lines()
93 .map(|line| format!("{}{}", " ".repeat($indentation), line))
94 .collect::<Vec<String>>()
95 .join("\n")
96 }};
97 ($obj:expr) => {{
98 $crate::indent!(4, $obj)
99 }};
100}
101#[macro_export]
102macro_rules! indent_objdump {
103 ($indentation:literal, $obj:expr) => {{
104 format!("{:#?}", $obj)
105 .lines()
106 .map(|line| format!("{}{}", " ".repeat($indentation), line))
107 .collect::<Vec<String>>()
108 .join("\n")
109 }};
110 ($obj:expr) => {{
111 $crate::indent_objdump!(4, $obj)
112 }};
113}
114
115#[macro_export]
116macro_rules! function_name {
117 () => {{
118 fn f() {}
119 fn type_name_of<T>(_: T) -> &'static str {
120 std::any::type_name::<T>()
121 }
122 let name = type_name_of(f);
123 let name = name
124 .strip_suffix("::f")
125 .unwrap()
126 .replace(format!("{}::", module_path!()).as_str(), "");
127 name
128 }};
129}
130
131#[macro_export]
132macro_rules! unexpected {
133 ($( $arg:expr ),* ) => {{
134 $(
135 let obj = format!("{:#?}", $arg);
136 eprintln!("{}", crate::color::reset([obj, $crate::location!(unexpected)].join(" ")));
137 )*
138 std::process::exit(107);
139 }};
140 () => {
141 $crate::unexpected!("reach");
142 };
143}
144#[macro_export]
145macro_rules! caller {
146 () => {
147 $crate::Caller($crate::function_name!().to_string(), file!().to_string(), line!())
148 };
149}
150
151#[macro_export]
152macro_rules! with_caller {
153 ($error:expr) => {{
154 use crate::Traceback;
155 $error.with($crate::caller!())
156 }};
157}
158
159#[macro_export]
160macro_rules! map_call_to_result {
161 ($result:expr) => {
162 $result.map_err(|error| $crate::with_caller!(crate::Error::from(error)))
163 };
164}
165#[macro_export]
166macro_rules! try_result {
167 ($result:expr) => {
168 crate::map_call_to_result!($result)?
169 };
170}
171
172#[macro_export]
173macro_rules! unwrap_result {
174 ($result:expr) => {{
175 use crate::Traceback;
176 $crate::map_call_to_result!($result).unwrap()
177 }};
178}
179
180#[macro_export]
181macro_rules! impl_error {
182 ($name:ident, $type:ty) => {
183 #[derive(Clone, PartialEq, Eq)]
184 pub struct Error {
185 message: String,
186 ty: $type,
187 callers: Vec<crate::Caller>,
188 previous: Option<Box<Error>>,
189 }
190 impl Error {
191 pub fn new<T: std::fmt::Display>(message: T, ty: $type) -> Self {
192 Self::with_previous_error(message, ty, None)
193 }
194
195 pub fn with_previous_error<T: std::fmt::Display>(
196 message: T,
197 ty: $type,
198 previous: Option<Error>,
199 ) -> Self {
200 let message = message.to_string();
201 Error {
202 message,
203 ty,
204 callers: Vec::new(),
205 previous: previous.map(Box::new),
206 }
207 }
208 }
209 impl std::error::Error for $name {}
210
211 impl $crate::Traceback for $name {
212 fn message(&self) -> String {
213 self.message.to_string()
214 }
215
216 fn callers(&self) -> Vec<$crate::Caller> {
217 self.callers.to_vec()
218 }
219
220 fn with(&self, caller: $crate::Caller) -> Self {
221 let mut error = self.clone();
222 error.callers.insert(0, caller);
223 error
224 }
225
226 fn previous_as_debug(&self) -> String {
227 self.previous.clone().map(|error| format!("{:#?}", error)).unwrap_or_default()
228 }
229
230 fn previous_as_string(&self) -> String {
231 self.previous.clone().map(|error| format!("{}", error)).unwrap_or_default()
232 }
233 }
234 impl std::fmt::Display for Error {
235 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
236 write!(f, "{}\n\nreason: {}", self.ty, self.highlight_message())
237 }
238 }
239 impl std::fmt::Debug for Error {
240 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
241 let ty = self.ty.to_string();
242 let source = self.to_string();
243 write!(
244 f,
245 "{}{}",
246 if ty == source {
247 ty.to_string()
248 } else {
249 format!("{} in source:\n{}", ty, source)
250 },
251 if self.callers.len() > 0 {
252 format!(
253 "\n\nStacktrace:\n{}\n",
254 [self.previous_as_debug(), self.callers_to_string(4)]
255 .iter()
256 .filter(|s| !s.trim().is_empty())
257 .map(String::from)
258 .collect::<Vec<String>>()
259 .join("\n")
260 )
261 } else {
262 String::new()
263 }
264 )
265 }
266 }
267 pub type Result<T> = std::result::Result<T, Error>;
268 #[macro_export]
269 macro_rules! try_result {
270 ($result: expr) => {
271 $crate::map_call_to_result!($result)?
272 };
273 }
274 #[macro_export]
275 macro_rules! map_call_to_result {
276 ($result: expr) => {
277 use crate::Traceback;
278 $result.map_err(|error| crate::with_caller!(crate::Error::from(error)))
279 };
280 }
281 };
282}
283
284#[macro_export]
285macro_rules! format_to_str {
286 (&$lifetime:lifetime $text:literal, $( $arg:expr ),* $(,)? ) => {
287 std::borrow::Cow::from(format!($text, $($arg,)*).as_str())
288 };
289}
290
291#[macro_export]
292macro_rules! vec_deque {
293 ($( $arg:expr ),* $(,)? ) => {{
294 let mut deque = std::collections::VecDeque::new();
295 $(deque.push_back($arg);
296 )*
297 deque
298 }};
299}
300
301#[macro_export]
302macro_rules! step {
303 ($text:literal) => {{
304 $crate::step!(length=80, $text)
305 }};
306 (fg=$fg:literal, $text:literal) => {{
307 $crate::step!(bg=$fg, fg=crate::color::invert_bw($fg), length=80, $text)
308 }};
309 (bg=$bg:expr, fg=$fg:expr, $text:literal) => {{
310 $crate::step!(bg=$bg, fg=$fg, length=80, $text)
311 }};
312 (length=$length:literal, $text:expr) => {{
313 let (bg, fg) = crate::color::couple(line!() as usize);
314 let text = $text.to_string();
315 let bar = crate::color::ansi(
316 " ".repeat($length),
317 fg.into(),
318 bg.into(),
319 );
320 eprintln!(
321 "\n{}",
322 [
323 bar.clone(),
324 crate::color::ansi(
325 if text.is_empty() { String::new() } else { format!("{}", text) },
326 fg.into(),
327 bg.into(),
328 ),
329 ].join("\n")
330 );
331
332 }};
333 (bg=$bg:expr, fg=$fg:expr, length=$length:literal, $text:expr) => {{
334 let text = $text.to_string();
335 let bar = crate::color::ansi(
336 " ".repeat($length),
337 $fg as usize,
338 $bg as usize,
339 );
340 eprintln!(
341 "\n{}",
342 [
343 bar.clone(),
344 crate::color::ansi(
345 if text.is_empty() { String::new() } else { format!("{}", text) },
346 $fg as usize,
347 $bg as usize,
348 ),
349 ].join("\n")
350 );
351 }};
352 (length=$length:literal, $text:literal, $( $arg:expr ),* $(,)? ) => {{
353 $crate::step!(length=$length, format_args!($text, $($arg,)*))
354 }};
355 () => {{
356 $crate::step!("")
357 }};
358}
359#[macro_export]
360macro_rules! step_test {
361 ($text:literal) => {{
362 $crate::step!(length=80, $text)
363 }};
364 (length=$length:literal, $text:literal, $( $arg:expr ),* $(,)? ) => {{
365 $crate::step!(length=$length, format_args!($text, $($arg,)*))
366 }};
367 (length=$length:literal, $text:expr) => {{
368 let (bg, fg) = crate::color::couple(line!() as usize);
369 let text = $text.to_string();
370 let bar = crate::color::ansi(
371 " ".repeat($length),
372 fg.into(),
373 bg.into(),
374 );
375 eprintln!(
376 "\n{}",
377 [
378 bar.clone(),
379 crate::color::ansi(
380 if text.is_empty() { String::new() } else { format!("{}", text) },
381 bg.into(),
382 fg.into(),
383 ),
384 bar.clone(),
385 ].join("\n")
386 );
387 }};
388 () => {{
389 $crate::step!("")
390 }};
391}
392
393#[macro_export]
394macro_rules! admonition {
395 ($color:literal, $message:expr) => {
396 $crate::admonition!($color, "{}", $message);
397 };
398 ($color:literal, $title:literal, $message:expr) => {
399 $crate::admonition!($color, title=$title, $message);
400 };
401
402 ($color:literal, title=$title:literal, $message:expr) => {
403 $crate::admonition!($color, title=$title, "{}", $message);
404 };
405 ($color:literal, title=$title:literal, $format:literal, $($arg:expr),* $(,)?) => {{
406 use crate::color;
407 eprintln!(
408 "\n{}",
409 [
410 color::ansi(
411 format!("{}:{} {}", crate::function_name!(), line!(), $title),
412 color::invert_bw($color).into(),
413 $color,
414 ),
415 color::ansi(
416 format!($format, $($arg),*),
417 $color,
418 color::invert_bw($color).into(),
419 )
420 ]
421 .join(" ")
422 );
423 }};
424 ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {{
425 use crate::color;
426 eprintln!(
427 "\n{}",
428 [
429 color::ansi(
430 format!("{}:{}", crate::function_name!(), line!()),
431 color::invert_bw($color).into(),
432 $color,
433 ),
434 color::ansi(
435 format!($format, $($arg),*),
436 $color,
437 color::invert_bw($color).into(),
438 )
439 ]
440 .join(" ")
441 );
442 }};
443}
444
445#[macro_export]
446macro_rules! warn {
447 ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {
448 $crate::admonition!($color, title="WARNING", $format, $($arg),*);
449 };
450 ($color:literal, $message:expr) => {
451 $crate::admonition!($color, title="WARNING", $message);
452 };
453 ($message:expr) => {
454 $crate::warn!(220, $message);
455 };
456}
457
458#[macro_export]
459macro_rules! info {
460 ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {
461 $crate::admonition!($color, title="INFO", $format, $($arg),*);
462 };
463 ($color:literal, $message:expr) => {
464 $crate::admonition!($color, title="INFO", $message);
465 };
466 ($message:expr) => {
467 $crate::info!(74, $message);
468 };
469}