carmen_lang/errors/
mod.rs

1//! Error handling module.
2//!
3//! This module provides the core error types and utilities used throughout the Carmen
4//! language implementation. It includes position tracking, error categorization, and
5//! convenient error handling patterns.
6
7pub mod reporter;
8
9use std::fmt;
10
11/// Represents a position in source code with line, column, and absolute offset.
12///
13/// Positions use 1-based indexing for line and column numbers to match
14/// conventional text editor behavior.
15#[derive(Debug, Clone, Copy, PartialEq)]
16pub struct Position {
17    /// Line number (1-based)
18    pub line: usize,
19    /// Column number (1-based)
20    pub column: usize,
21    /// Absolute character offset from the beginning of the source (0-based)
22    pub offset: usize,
23}
24
25impl Default for Position {
26    fn default() -> Self {
27        Self {
28            line: 1,
29            column: 1,
30            offset: 0,
31        }
32    }
33}
34
35impl Position {
36    /// Creates a new position with the given line, column, and offset.
37    pub fn new(line: usize, column: usize, offset: usize) -> Self {
38        Self {
39            line,
40            column,
41            offset,
42        }
43    }
44
45    /// Creates a position representing the start of a source file.
46    pub fn start() -> Self {
47        Self {
48            line: 1,
49            column: 1,
50            offset: 0,
51        }
52    }
53}
54
55impl fmt::Display for Position {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        write!(f, "{}:{}", self.line, self.column)
58    }
59}
60
61/// Represents a range in source code from a start position to an end position.
62///
63/// Used to track the location of tokens, expressions, and errors in the source.
64#[derive(Debug, Clone, Copy, PartialEq)]
65pub struct Span {
66    pub start: Position,
67    pub end: Position,
68}
69
70impl Span {
71    pub fn new(start: Position, end: Position) -> Self {
72        Self { start, end }
73    }
74
75    /// Creates a span that covers a single position (zero-width span).
76    pub fn single(pos: Position) -> Self {
77        Self {
78            start: pos,
79            end: pos,
80        }
81    }
82}
83
84/// A span-less error representing the source of the problem.
85#[derive(Debug, Clone, PartialEq)]
86pub enum ErrorSource {
87    Lexical(String),
88    Parsing(String),
89    Runtime(String),
90    Type(String),
91    Music(String),
92    Argument(String),
93    Cli(String),
94}
95
96impl ErrorSource {
97    /// Returns a human-readable string describing the error type.
98    pub fn type_str(&self) -> &'static str {
99        match self {
100            ErrorSource::Lexical(_) => "Lexical error",
101            ErrorSource::Parsing(_) => "Parsing error",
102            ErrorSource::Runtime(_) => "Runtime error",
103            ErrorSource::Type(_) => "Type error",
104            ErrorSource::Music(_) => "Music error",
105            ErrorSource::Argument(_) => "Argument error",
106            ErrorSource::Cli(_) => "CLI error",
107        }
108    }
109}
110
111impl fmt::Display for ErrorSource {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        match self {
114            ErrorSource::Lexical(s)
115            | ErrorSource::Parsing(s)
116            | ErrorSource::Runtime(s)
117            | ErrorSource::Type(s)
118            | ErrorSource::Music(s)
119            | ErrorSource::Argument(s)
120            | ErrorSource::Cli(s) => write!(f, "{s}"),
121        }
122    }
123}
124
125impl std::error::Error for ErrorSource {}
126
127/// The main error type for the application, combining a source and a span.
128#[derive(Debug, Clone, PartialEq)]
129pub struct CarmenError {
130    pub source: ErrorSource,
131    pub span: Span,
132}
133
134impl CarmenError {
135    /// Creates a new Carmen error with the given source and location span.
136    pub fn new(source: ErrorSource, span: Span) -> Self {
137        Self { source, span }
138    }
139}
140
141impl fmt::Display for CarmenError {
142    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143        write!(
144            f,
145            "{}: {} (at {})",
146            self.source.type_str(),
147            self.source,
148            self.span.start
149        )
150    }
151}
152
153impl std::error::Error for CarmenError {
154    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
155        Some(&self.source)
156    }
157}
158
159/// A trait for conveniently adding a span to an `ErrorSource`.
160pub trait AddSpan {
161    /// Converts an `ErrorSource` into a `CarmenError` by adding span information.
162    fn with_span(self, span: Span) -> CarmenError;
163}
164
165impl AddSpan for ErrorSource {
166    fn with_span(self, span: Span) -> CarmenError {
167        CarmenError::new(self, span)
168    }
169}
170
171/// The default result type for most fallible operations in the language pipeline.
172pub type Result<T> = std::result::Result<T, CarmenError>;
173
174/// A result type for core logic that does not have access to span information.
175pub type CoreResult<T> = std::result::Result<T, ErrorSource>;