Skip to main content

trueno_ptx_debug/parser/
error.rs

1//! Parser error types
2
3use super::ast::SourceLocation;
4
5/// Parse error types
6#[derive(Debug, Clone, thiserror::Error)]
7pub enum ParseError {
8    /// Unexpected token
9    #[error("Unexpected token at {location}: expected {expected}, found {found}")]
10    UnexpectedToken {
11        /// Expected token description
12        expected: String,
13        /// Found token description
14        found: String,
15        /// Source location
16        location: SourceLocation,
17    },
18
19    /// Unexpected end of file
20    #[error("Unexpected end of file at {location}")]
21    UnexpectedEof {
22        /// Source location
23        location: SourceLocation,
24    },
25
26    /// Invalid directive
27    #[error("Invalid directive '{directive}' at {location}")]
28    InvalidDirective {
29        /// Directive text
30        directive: String,
31        /// Source location
32        location: SourceLocation,
33    },
34
35    /// Invalid instruction
36    #[error("Invalid instruction at {location}: {message}")]
37    InvalidInstruction {
38        /// Error message
39        message: String,
40        /// Source location
41        location: SourceLocation,
42    },
43
44    /// Invalid operand
45    #[error("Invalid operand '{operand}' at {location}")]
46    InvalidOperand {
47        /// Operand text
48        operand: String,
49        /// Source location
50        location: SourceLocation,
51    },
52
53    /// Invalid type
54    #[error("Invalid type '{ty}' at {location}")]
55    InvalidType {
56        /// Type text
57        ty: String,
58        /// Source location
59        location: SourceLocation,
60    },
61
62    /// Duplicate label
63    #[error("Duplicate label '{label}' at {location}")]
64    DuplicateLabel {
65        /// Label name
66        label: String,
67        /// Source location
68        location: SourceLocation,
69    },
70
71    /// Undefined label
72    #[error("Undefined label '{label}' at {location}")]
73    UndefinedLabel {
74        /// Label name
75        label: String,
76        /// Source location
77        location: SourceLocation,
78    },
79
80    /// Lexer error
81    #[error("Lexer error at {location}: {message}")]
82    LexerError {
83        /// Error message
84        message: String,
85        /// Source location
86        location: SourceLocation,
87    },
88}
89
90impl ParseError {
91    /// Get the source location of the error
92    pub fn location(&self) -> &SourceLocation {
93        match self {
94            ParseError::UnexpectedToken { location, .. } => location,
95            ParseError::UnexpectedEof { location, .. } => location,
96            ParseError::InvalidDirective { location, .. } => location,
97            ParseError::InvalidInstruction { location, .. } => location,
98            ParseError::InvalidOperand { location, .. } => location,
99            ParseError::InvalidType { location, .. } => location,
100            ParseError::DuplicateLabel { location, .. } => location,
101            ParseError::UndefinedLabel { location, .. } => location,
102            ParseError::LexerError { location, .. } => location,
103        }
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110
111    #[test]
112    fn test_error_display() {
113        let err = ParseError::UnexpectedToken {
114            expected: "identifier".into(),
115            found: "number".into(),
116            location: SourceLocation {
117                line: 10,
118                column: 5,
119                file: None,
120            },
121        };
122        let msg = format!("{}", err);
123        assert!(msg.contains("Unexpected token"));
124        assert!(msg.contains("10:5"));
125    }
126
127    #[test]
128    fn test_error_location() {
129        let loc = SourceLocation {
130            line: 42,
131            column: 10,
132            file: None,
133        };
134        let err = ParseError::InvalidDirective {
135            directive: ".foo".into(),
136            location: loc.clone(),
137        };
138        assert_eq!(err.location().line, 42);
139        assert_eq!(err.location().column, 10);
140    }
141}