zenith_core/error.rs
1//! Parse error types for zenith-core.
2
3use crate::ast::Span;
4
5/// Codes that identify the category of a parse error.
6#[derive(Debug, Clone, PartialEq)]
7pub enum ParseErrorCode {
8 /// The input bytes are not valid UTF-8.
9 NotUtf8,
10 /// The UTF-8 source is not valid KDL.
11 InvalidKdl,
12 /// No top-level `zenith` node was found in the document.
13 MissingZenithRoot,
14 /// A node appeared in a context where it is not expected.
15 UnexpectedNode,
16 /// A property value could not be parsed into the expected type.
17 InvalidPropertyValue,
18}
19
20/// A single error emitted by the parse layer.
21#[derive(Debug, Clone, PartialEq)]
22pub struct ParseError {
23 /// Source span of the offending token or node, if available.
24 pub span: Option<Span>,
25 /// Stable error category code.
26 pub code: ParseErrorCode,
27 /// Human-readable description of the error.
28 pub message: String,
29}
30
31impl ParseError {
32 /// Construct a `ParseError` without a source span.
33 pub fn spanless(code: ParseErrorCode, message: impl Into<String>) -> Self {
34 Self {
35 span: None,
36 code,
37 message: message.into(),
38 }
39 }
40
41 /// Construct a `ParseError` with an explicit source span.
42 pub fn with_span(code: ParseErrorCode, span: Span, message: impl Into<String>) -> Self {
43 Self {
44 span: Some(span),
45 code,
46 message: message.into(),
47 }
48 }
49}
50
51impl std::fmt::Display for ParseError {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 write!(f, "{}", self.message)
54 }
55}
56
57impl std::error::Error for ParseError {}
58
59/// An error emitted by the format layer.
60///
61/// In practice, formatting the minimal v0 node set never fails — return `Err`
62/// only for genuinely un-serializable states (unreachable in valid input, but
63/// the fallible signature is the contract from the format spec).
64#[derive(Debug, Clone, PartialEq)]
65pub struct FormatError {
66 /// Human-readable description of why formatting failed.
67 pub message: String,
68}
69
70impl FormatError {
71 /// Construct a `FormatError` with the given message.
72 pub fn new(message: impl Into<String>) -> Self {
73 Self {
74 message: message.into(),
75 }
76 }
77}
78
79impl std::fmt::Display for FormatError {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 write!(f, "{}", self.message)
82 }
83}
84
85impl std::error::Error for FormatError {}