1use probl_syntax::{Diagnostic, Span};
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub enum ErrorKind {
8 Language,
10 Unsupported,
12 Limit,
14 Internal,
16}
17
18pub use probl_sema::ir::Fault;
19
20#[derive(Clone, Debug, PartialEq)]
23pub struct OpError {
24 pub message: String,
25 pub help: Option<String>,
26 pub kind: ErrorKind,
27 pub fault: Option<Fault>,
28}
29
30impl OpError {
31 pub fn new(message: impl Into<String>) -> OpError {
32 OpError {
33 message: message.into(),
34 help: None,
35 kind: ErrorKind::Language,
36 fault: None,
37 }
38 }
39
40 pub fn fault(fault: Fault, message: impl Into<String>) -> OpError {
42 OpError {
43 fault: Some(fault),
44 ..OpError::new(message)
45 }
46 }
47
48 pub fn as_fault(mut self, fault: Fault) -> OpError {
50 if self.kind == ErrorKind::Language {
51 self.fault = Some(fault);
52 }
53 self
54 }
55
56 pub fn unsupported(message: impl Into<String>) -> OpError {
57 OpError {
58 kind: ErrorKind::Unsupported,
59 ..OpError::new(message)
60 }
61 }
62
63 pub fn limit(message: impl Into<String>) -> OpError {
64 OpError {
65 kind: ErrorKind::Limit,
66 ..OpError::new(message)
67 }
68 }
69
70 pub fn internal(message: impl Into<String>) -> OpError {
72 OpError {
73 kind: ErrorKind::Internal,
74 ..OpError::new(message)
75 }
76 .help("this is a bug in Probl; please report it with the program that caused it")
77 }
78
79 pub fn help(mut self, help: impl Into<String>) -> OpError {
80 self.help = Some(help.into());
81 self
82 }
83
84 pub fn at(self, span: Span) -> RuntimeError {
85 RuntimeError {
86 message: self.message,
87 span,
88 notes: Vec::new(),
89 help: self.help,
90 kind: self.kind,
91 fault: self.fault,
92 }
93 }
94}
95
96pub type OpResult<T> = std::result::Result<T, OpError>;
97
98impl From<probl_number::IntError> for OpError {
99 fn from(error: probl_number::IntError) -> Self {
100 match error {
101 probl_number::IntError::TooLarge => Self::limit(error.to_string()),
102 probl_number::IntError::DivisionByZero => Self::fault(Fault::DivisionByZero, error.to_string()),
103 _ => Self::new(error.to_string()),
104 }
105 }
106}
107
108#[derive(Clone, Debug, PartialEq)]
109pub struct RuntimeError {
110 pub message: String,
111 pub span: Span,
112 pub notes: Vec<String>,
113 pub help: Option<String>,
114 pub kind: ErrorKind,
115 pub fault: Option<Fault>,
116}
117
118impl RuntimeError {
119 pub fn new(span: Span, message: impl Into<String>) -> RuntimeError {
120 OpError::new(message).at(span)
121 }
122
123 pub fn limit(span: Span, message: impl Into<String>) -> RuntimeError {
124 OpError::limit(message).at(span)
125 }
126
127 pub fn with_note(mut self, note: impl Into<String>) -> RuntimeError {
128 self.notes.push(note.into());
129 self
130 }
131
132 pub fn with_help(mut self, help: impl Into<String>) -> RuntimeError {
133 self.help = Some(help.into());
134 self
135 }
136
137 pub fn as_fault(mut self, fault: Fault) -> RuntimeError {
139 if self.kind == ErrorKind::Language {
140 self.fault = Some(fault);
141 }
142 self
143 }
144
145 pub fn to_diagnostic(&self) -> Diagnostic {
146 let mut d = Diagnostic::error(self.span, &self.message);
147 d.notes = self.notes.clone();
148 d.help = self.help.clone();
149 d
150 }
151}
152
153pub type Result<T> = std::result::Result<T, RuntimeError>;