Skip to main content

wit_parser/ast/
error.rs

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