Skip to main content

rill_lang/
error.rs

1//! Source spans and the unified compile error type.
2
3use thiserror::Error;
4
5/// A half-open byte range `[start, end)` into the original source string.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct Span {
8    /// Start byte offset (inclusive).
9    pub start: usize,
10    /// End byte offset (exclusive).
11    pub end: usize,
12}
13
14impl Span {
15    /// Construct a span from a start and end byte offset.
16    pub fn new(start: usize, end: usize) -> Self {
17        Self { start, end }
18    }
19
20    /// A span covering both `self` and `other`.
21    pub fn merge(self, other: Span) -> Span {
22        Span::new(self.start.min(other.start), self.end.max(other.end))
23    }
24}
25
26/// Any error produced while compiling rill-lang source.
27#[derive(Error, Debug, Clone, PartialEq)]
28pub enum CompileError {
29    /// The lexer hit a character it cannot start a token with.
30    #[error("lex error at {span:?}: {msg}")]
31    Lex {
32        /// Human-readable cause.
33        msg: String,
34        /// Location in source.
35        span: Span,
36    },
37    /// The parser encountered unexpected or missing tokens.
38    #[error("parse error at {span:?}: {msg}")]
39    Parse {
40        /// Human-readable cause.
41        msg: String,
42        /// Location in source.
43        span: Span,
44    },
45    /// The type checker rejected the program (arity or scalar mismatch, etc.).
46    #[error("type error at {span:?}: {msg}")]
47    Type {
48        /// Human-readable cause.
49        msg: String,
50        /// Location in source.
51        span: Span,
52    },
53    /// A well-typed program that the MVP backend cannot lower/run.
54    #[error("unsupported: {0}")]
55    Unsupported(String),
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn span_merge_covers_both() {
64        let a = Span::new(2, 5);
65        let b = Span::new(8, 10);
66        assert_eq!(a.merge(b), Span::new(2, 10));
67    }
68}