roan_error/
frame.rs

1use crate::TextSpan;
2use colored::Colorize;
3use std::{fmt::Debug, path::PathBuf};
4
5/// A frame represents a single function call.
6///
7/// It provides info of which function is being executed. This helps in debugging and error reporting.
8#[derive(Clone)]
9pub struct Frame {
10    /// The name of the function being executed.
11    pub name: String,
12    /// The span of the function in the source code.
13    pub span: TextSpan,
14    /// The path of the file where the function is defined.
15    pub path: String,
16}
17
18impl Frame {
19    /// Creates a new `Frame` with the specified name, span, and path.
20    ///
21    /// # Parameters
22    /// - `name` - The name of the function.
23    /// - `span` - The span of the function in the source code.
24    /// - `path` - The path of the file where the function is defined.
25    ///
26    /// # Returns
27    /// The new `Frame`.
28    ///
29    /// # Examples
30    /// ```rust
31    /// use roan_error::{Position, TextSpan};
32    /// use roan_error::frame::Frame;
33    /// let frame = Frame::new("main", TextSpan::new(Position::new(1,1,1), Position::new(1,1,1), "main".into()), ".\\src\\main.roan");
34    /// ```
35    pub fn new(name: impl Into<String>, span: TextSpan, path: impl Into<String>) -> Self {
36        Self {
37            name: name.into(),
38            span,
39            path: path.into(),
40        }
41    }
42
43    /// If path is None returns "unknown" otherwise returns the path.
44    pub fn path_or_unknown(path: Option<PathBuf>) -> String {
45        let path = path
46            .map(PathBuf::from)
47            .unwrap_or_else(|| PathBuf::from("unknown"));
48
49        path.to_string_lossy().to_string()
50    }
51}
52
53impl Debug for Frame {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        write!(
56            f,
57            "   {} {} {}{}{}{}{}",
58            "at".dimmed(),
59            self.name.bold(),
60            self.path.cyan(),
61            ":".dimmed(),
62            self.span.start.line.to_string().yellow(),
63            ":".dimmed(),
64            self.span.start.column.to_string().dimmed().yellow()
65        )
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72    use crate::Position;
73
74    #[test]
75    fn test_frame_new() {
76        let frame = Frame::new(
77            "main",
78            TextSpan::new(
79                Position::new(1, 1, 1),
80                Position::new(1, 1, 1),
81                "main".into(),
82            ),
83            ".\\src\\main.roan",
84        );
85
86        assert_eq!(frame.name, "main");
87        assert_eq!(frame.span.start.line, 1);
88        assert_eq!(frame.span.start.column, 1);
89        assert_eq!(frame.path, ".\\src\\main.roan");
90    }
91
92    #[test]
93    fn test_frame_path_or_unknown() {
94        let path = Some(PathBuf::from("tests\\test.roan"));
95        assert_eq!(Frame::path_or_unknown(path), "tests\\test.roan");
96
97        let path = None;
98        assert_eq!(Frame::path_or_unknown(path), "unknown");
99    }
100}