shrew_ir/
error.rs

1// Error types for shrew-ir
2
3use crate::token::Span;
4use std::fmt;
5
6/// Result type for the IR crate.
7pub type Result<T> = std::result::Result<T, Error>;
8
9/// All errors that can occur during lexing, parsing, or IR construction.
10#[derive(Debug, Clone)]
11pub struct Error {
12    pub kind: ErrorKind,
13    pub span: Option<Span>,
14    pub source_line: Option<String>,
15}
16
17#[derive(Debug, Clone)]
18pub enum ErrorKind {
19    // Lexer errors
20    UnexpectedChar(char),
21    UnterminatedString,
22    UnterminatedComment,
23    InvalidNumber(String),
24    UnknownDirective(String),
25
26    // Parser errors
27    UnexpectedToken { expected: String, got: String },
28    UnexpectedEof,
29    InvalidDType(String),
30
31    // General
32    Message(String),
33}
34
35impl Error {
36    pub fn new(kind: ErrorKind, span: Span) -> Self {
37        Self {
38            kind,
39            span: Some(span),
40            source_line: None,
41        }
42    }
43
44    pub fn msg(s: impl Into<String>) -> Self {
45        Self {
46            kind: ErrorKind::Message(s.into()),
47            span: None,
48            source_line: None,
49        }
50    }
51
52    pub fn with_source_line(mut self, line: String) -> Self {
53        self.source_line = Some(line);
54        self
55    }
56}
57
58impl fmt::Display for Error {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        if let Some(span) = &self.span {
61            write!(f, "[{}:{}] ", span.line, span.col)?;
62        }
63        match &self.kind {
64            ErrorKind::UnexpectedChar(c) => write!(f, "unexpected character '{c}'"),
65            ErrorKind::UnterminatedString => write!(f, "unterminated string literal"),
66            ErrorKind::UnterminatedComment => write!(f, "unterminated block comment"),
67            ErrorKind::InvalidNumber(s) => write!(f, "invalid number '{s}'"),
68            ErrorKind::UnknownDirective(s) => write!(f, "unknown directive '@{s}'"),
69            ErrorKind::UnexpectedToken { expected, got } => {
70                write!(f, "expected {expected}, got {got}")
71            }
72            ErrorKind::UnexpectedEof => write!(f, "unexpected end of file"),
73            ErrorKind::InvalidDType(s) => write!(f, "invalid dtype '{s}'"),
74            ErrorKind::Message(s) => write!(f, "{s}"),
75        }?;
76        if let Some(line) = &self.source_line {
77            write!(f, "\n  | {line}")?;
78            if let Some(span) = &self.span {
79                write!(f, "\n  | {}^", " ".repeat(span.col.saturating_sub(1)))?;
80            }
81        }
82        Ok(())
83    }
84}
85
86impl std::error::Error for Error {}