Coverage Report

Created: 2026-06-07 07:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm-tools/crates/wit-parser/src/ast/error.rs
Line
Count
Source
1
//! Error types for WIT parsing.
2
3
use alloc::boxed::Box;
4
use alloc::string::{String, ToString};
5
use core::fmt;
6
7
use crate::{SourceMap, Span, ast::lex};
8
9
/// Convenience alias for a `Result` whose error type is [`ParseError`].
10
pub 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)]
15
pub 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
37
impl ParseErrorKind {
38
    /// Returns the source span associated with this error.
39
0
    pub fn span(&self) -> Span {
40
0
        match self {
41
0
            ParseErrorKind::Lex(e) => Span::new(e.position(), e.position() + 1),
42
0
            ParseErrorKind::Syntax { span, .. }
43
0
            | ParseErrorKind::ItemNotFound { span, .. }
44
0
            | ParseErrorKind::TypeCycle { span, .. } => *span,
45
        }
46
0
    }
47
}
48
49
impl fmt::Display for ParseErrorKind {
50
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51
0
        match self {
52
0
            ParseErrorKind::Lex(e) => fmt::Display::fmt(e, f),
53
0
            ParseErrorKind::Syntax { message, .. } => message.fmt(f),
54
            ParseErrorKind::ItemNotFound {
55
0
                kind, name, hint, ..
56
            } => {
57
0
                write!(f, "{kind} `{name}` does not exist")?;
58
0
                if let Some(hint) = hint {
59
0
                    write!(f, "\n{hint}")?;
60
0
                }
61
0
                Ok(())
62
            }
63
0
            ParseErrorKind::TypeCycle { kind, name, .. } => {
64
0
                write!(f, "{kind} `{name}` depends on itself")
65
            }
66
        }
67
0
    }
68
}
69
70
/// A single structured error from parsing a WIT package.
71
#[derive(Debug, PartialEq, Eq)]
72
pub struct ParseError(Box<ParseErrorKind>);
73
74
impl ParseError {
75
0
    pub fn new_syntax(span: Span, message: impl Into<String>) -> Self {
76
0
        ParseErrorKind::Syntax {
77
0
            span,
78
0
            message: message.into(),
79
0
        }
80
0
        .into()
81
0
    }
82
83
    /// Returns the underlying error kind
84
0
    pub fn kind(&self) -> &ParseErrorKind {
85
0
        &self.0
86
0
    }
87
88
    /// Returns the underlying error kind (mutable).
89
0
    pub fn kind_mut(&mut self) -> &mut ParseErrorKind {
90
0
        &mut self.0
91
0
    }
92
93
    /// Format this error with source context (file:line:col + snippet)
94
0
    pub fn highlight(&self, source_map: &SourceMap) -> String {
95
0
        let e = self.kind();
96
0
        source_map
97
0
            .highlight_span(e.span(), e)
98
0
            .unwrap_or_else(|| e.to_string())
99
0
    }
100
}
101
102
impl fmt::Display for ParseError {
103
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104
0
        fmt::Display::fmt(self.kind(), f)
105
0
    }
106
}
107
108
impl core::error::Error for ParseError {}
109
110
impl From<ParseErrorKind> for ParseError {
111
0
    fn from(kind: ParseErrorKind) -> Self {
112
0
        ParseError(Box::new(kind))
113
0
    }
114
}
115
116
impl From<lex::Error> for ParseError {
117
0
    fn from(e: lex::Error) -> Self {
118
0
        ParseErrorKind::Lex(e).into()
119
0
    }
120
}