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}