Skip to main content

wit_parser/ast/
error.rs

1use alloc::boxed::Box;
2use alloc::string::{String, ToString};
3use core::fmt;
4
5use crate::{SourceMap, Span, ast::lex};
6
7pub type ParseResult<T, E = ParseError> = Result<T, E>;
8
9#[non_exhaustive]
10#[derive(Debug, PartialEq, Eq)]
11pub enum ParseErrorKind {
12    /// Lexer error (invalid character, unterminated comment, etc.)
13    Lex(lex::Error),
14    /// Syntactic or semantic error within a single package (duplicate name,
15    /// invalid attribute, etc.)
16    Syntax { span: Span, message: String },
17    /// A type/interface/world references a name that does not exist within
18    /// the same package.
19    ItemNotFound {
20        span: Span,
21        name: String,
22        kind: String,
23        hint: Option<String>,
24    },
25    /// A type/interface/world depends on itself.
26    TypeCycle {
27        span: Span,
28        name: String,
29        kind: String,
30    },
31}
32
33impl ParseErrorKind {
34    pub fn span(&self) -> Span {
35        match self {
36            ParseErrorKind::Lex(e) => Span::new(e.position(), e.position() + 1),
37            ParseErrorKind::Syntax { span, .. }
38            | ParseErrorKind::ItemNotFound { span, .. }
39            | ParseErrorKind::TypeCycle { span, .. } => *span,
40        }
41    }
42}
43
44impl fmt::Display for ParseErrorKind {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        match self {
47            ParseErrorKind::Lex(e) => fmt::Display::fmt(e, f),
48            ParseErrorKind::Syntax { message, .. } => message.fmt(f),
49            ParseErrorKind::ItemNotFound {
50                kind, name, hint, ..
51            } => {
52                write!(f, "{kind} `{name}` does not exist")?;
53                if let Some(hint) = hint {
54                    write!(f, "\n{hint}")?;
55                }
56                Ok(())
57            }
58            ParseErrorKind::TypeCycle { kind, name, .. } => {
59                write!(f, "{kind} `{name}` depends on itself")
60            }
61        }
62    }
63}
64
65#[derive(Debug, PartialEq, Eq)]
66pub struct ParseError(Box<ParseErrorKind>);
67
68impl ParseError {
69    pub fn new_syntax(span: Span, message: impl Into<String>) -> Self {
70        ParseErrorKind::Syntax {
71            span,
72            message: message.into(),
73        }
74        .into()
75    }
76
77    pub fn kind(&self) -> &ParseErrorKind {
78        &self.0
79    }
80
81    pub fn kind_mut(&mut self) -> &mut ParseErrorKind {
82        &mut self.0
83    }
84
85    /// Format this error with source context (file:line:col + snippet)
86    pub fn highlight(&self, source_map: &SourceMap) -> String {
87        let e = self.kind();
88        source_map
89            .highlight_span(e.span(), e)
90            .unwrap_or_else(|| e.to_string())
91    }
92}
93
94impl fmt::Display for ParseError {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        fmt::Display::fmt(self.kind(), f)
97    }
98}
99
100impl core::error::Error for ParseError {}
101
102impl From<ParseErrorKind> for ParseError {
103    fn from(kind: ParseErrorKind) -> Self {
104        ParseError(Box::new(kind))
105    }
106}
107
108impl From<lex::Error> for ParseError {
109    fn from(e: lex::Error) -> Self {
110        ParseErrorKind::Lex(e).into()
111    }
112}