Skip to main content

rill_lang/
error.rs

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