dice_rust/
error.rs

1use std::fmt;
2use thiserror::Error;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct Position {
6    pub line: u32,
7    pub column: u32,
8    pub offset: u32,
9}
10
11impl Position {
12    pub fn new(line: u32, column: u32, offset: u32) -> Self {
13        Self {
14            line,
15            column,
16            offset,
17        }
18    }
19}
20
21impl fmt::Display for Position {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        write!(f, "{}:{}", self.line, self.column)
24    }
25}
26
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct Span {
29    pub start: Position,
30    pub end: Position,
31}
32
33impl Span {
34    pub fn new(start: Position, end: Position) -> Self {
35        Self { start, end }
36    }
37
38    pub fn single(pos: Position) -> Self {
39        Self {
40            start: pos,
41            end: pos,
42        }
43    }
44}
45
46impl fmt::Display for Span {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        if self.start.line == self.end.line {
49            write!(f, "{}:{}", self.start.line, self.start.column)
50        } else {
51            write!(f, "{}-{}", self.start, self.end)
52        }
53    }
54}
55
56#[derive(Error, Debug)]
57pub enum ParseError {
58    #[error("Lexical error at {span}: {message}")]
59    LexicalError { span: Span, message: String },
60
61    #[error("Syntax error at {span}: {message}")]
62    SyntaxError { span: Span, message: String },
63
64    #[error("Unexpected token at {span}: expected {expected}, found {found}")]
65    UnexpectedToken {
66        span: Span,
67        expected: String,
68        found: String,
69    },
70
71    #[error("Unexpected end of input")]
72    UnexpectedEndOfInput,
73
74    #[error("Invalid number literal at {span}: {message}")]
75    InvalidNumberLiteral { span: Span, message: String },
76}
77
78impl ParseError {
79    pub fn lexical_error(span: Span, message: impl Into<String>) -> Self {
80        Self::LexicalError {
81            span,
82            message: message.into(),
83        }
84    }
85
86    pub fn syntax_error(span: Span, message: impl Into<String>) -> Self {
87        Self::SyntaxError {
88            span,
89            message: message.into(),
90        }
91    }
92
93    pub fn unexpected_token(
94        span: Span,
95        expected: impl Into<String>,
96        found: impl Into<String>,
97    ) -> Self {
98        Self::UnexpectedToken {
99            span,
100            expected: expected.into(),
101            found: found.into(),
102        }
103    }
104
105    pub fn unexpected_end_of_input() -> Self {
106        Self::UnexpectedEndOfInput
107    }
108
109    pub fn invalid_number_literal(span: Span, message: impl Into<String>) -> Self {
110        Self::InvalidNumberLiteral {
111            span,
112            message: message.into(),
113        }
114    }
115}
116
117#[derive(Error, Debug)]
118pub enum SemanticError {
119    #[error("Empty program")]
120    EmptyProgram,
121    #[error("Dice count cannot be zero")]
122    DiceCountZero,
123    #[error("Dice faces cannot be zero")]
124    DiceFacesZero,
125}
126
127#[derive(Error, Debug)]
128pub enum RuntimeError {
129    #[error("Invalid stack state")]
130    InvalidStackState,
131    #[error("Stack underflow")]
132    StackUnderflow,
133    #[error("Stack overflow")]
134    StackOverflow,
135    #[error("Division by zero")]
136    DivisionByZero,
137    #[error("Invalid instruction pointer: {0}")]
138    InvalidInstructionPointer(usize),
139    #[error("Invalid opcode: {0}")]
140    InvalidOpcode(u8),
141    #[error(
142        "Unknown constant pool tag: {tag} at index {index}. Valid tags: 1=Utf8, 3=Integer, 4=Float, 5=Long, 6=Double, 7=Class, 8=String, 9=Fieldref, 10=Methodref, 11=InterfaceMethodref, 12=NameAndType, 15=MethodHandle, 16=MethodType, 18=InvokeDynamic"
143    )]
144    UnknownConstantPoolTag { tag: u8, index: u16 },
145    #[error("Call stack overflow")]
146    CallStackOverflow,
147    #[error("Call stack underflow")]
148    CallStackUnderflow,
149}