Reduct  v4.0.5-1-g4851deb
A functional and immutable language.
Loading...
Searching...
No Matches
error.h
Go to the documentation of this file.
1#ifndef REDUCT_ERROR_H
2#define REDUCT_ERROR_H 1
3
4#include <reduct/defs.h>
5
6struct reduct;
7struct reduct_item;
8
9#include <assert.h>
10#include <setjmp.h>
11#include <stdio.h>
12#include <stdlib.h>
13
14/**
15 * @file error.h
16 * @brief Error handling and reporting.
17 * @defgroup error Error
18 *
19 * @{
20 */
21
22#define REDUCT_ERROR_MAX_LEN 128 ///< Maximum length of an error string.
23#define REDUCT_ERROR_BACKTRACE_MAX 8 ///< Maximum number of backtrace frames.
24
25/**
26 * @brief Error type enumeration.
27 * @enum reduct_error_type_t
28 */
37
38/**
39 * @brief Backtrace frame structure.
40 * @struct reduct_error_frame_t
41 *
42 * Stores the source location for a single frame of the call stack at the time of a runtime error.
43 */
44typedef struct reduct_error_frame
45{
46 reduct_input_id_t inputId; ///< The input ID of the source file.
47 uint32_t position; ///< The position in the input buffer.
49
50/**
51 * @brief Error structure.
52 * @struct reduct_error_t
53 */
54typedef struct reduct_error
55{
56 const char* input; ///< The input buffer.
57 size_t inputLength; ///< The total length of the input buffer.
58 const char* path; ///< The path to the file that caused the error.
59 size_t regionLength; ///< The length of the region that caused the error.
60 size_t index; ///< The index of the region in the input buffer that caused the error.
61 jmp_buf jmp;
62 reduct_error_type_t type; ///< The type of the error.
63 char message[REDUCT_ERROR_MAX_LEN];
64 struct reduct_error* prev; ///< Previous error handler in the stack.
65 struct reduct* reduct; ///< The owning Reduct structure.
66 reduct_error_frame_t frames[REDUCT_ERROR_BACKTRACE_MAX]; ///< Backtrace frames for the error.
67 uint8_t frameCount; ///< The number of backtrace frames.
69
70/**
71 * @brief Create a Reduct error structure.
72 *
73 * @return A new Reduct error structure initialized to zero.
74 */
75#define REDUCT_ERROR() ((reduct_error_t){0})
76
77/**
78 * @brief Format and print the error to a file.
79 *
80 * @param error Pointer to the error structure.
81 * @param file The file to print to.
82 */
84
85/**
86 * @brief Get the row and column by traversing the input buffer.
87 *
88 * @param error Pointer to the error structure.
89 * @param row Pointer to the row variable.
90 * @param column Pointer to the column variable.
91 */
92REDUCT_API void reduct_error_get_row_column(reduct_error_t* error, size_t* row, size_t* column);
93
94/**
95 * @brief Set the error information in the error structure.
96 *
97 * @param error Pointer to the error structure.
98 * @param path The path to the file where the error occurred.
99 * @param input The input buffer where the error occurred.
100 * @param inputLength The total length of the input buffer.
101 * @param regionLength The length of the token/region that caused the error.
102 * @param position The position in the input buffer where the error occurred.
103 * @param type The type of the error.
104 * @param message The error message format string.
105 * @param ... The arguments for the format string.
106 */
107REDUCT_API void reduct_error_set(reduct_error_t* error, const char* path, const char* input, size_t inputLength,
108 size_t regionLength, size_t position, reduct_error_type_t type, const char* message, ...);
109
110/**
111 * @brief Get the error parameters from a Reduct item.
112 *
113 * @param reduct Pointer to the Reduct structure.
114 * @param item Pointer to the item.
115 * @param path Pointer to the path variable.
116 * @param input Pointer to the input variable.
117 * @param inputLength Pointer to the input length variable.
118 * @param regionLength Pointer to the region length variable.
119 * @param position Pointer to the position variable.
120 */
121REDUCT_API void reduct_error_get_item_params(struct reduct* reduct, struct reduct_item* item, const char** path,
122 const char** input, size_t* inputLength, size_t* regionLength, size_t* position);
123
124/**
125 * @brief Throw a runtime error utilizing the evaluation state to determine the context.
126 *
127 * @param reduct Pointer to the Reduct structure.
128 * @param message The error message format string.
129 * @param ... Additional arguments.
130 */
131REDUCT_API REDUCT_NORETURN void reduct_error_throw_runtime(struct reduct* reduct, const char* message, ...);
132
133/**
134 * @brief Push a new error handler onto the stack.
135 *
136 * This will cause the provided error handler to be called when an error occurs instead of the previous one.
137 *
138 * @param reduct Pointer to the Reduct structure.
139 * @param error Pointer to the error structure to push.
140 */
141REDUCT_API void reduct_error_push(struct reduct* reduct, reduct_error_t* error);
142
143/**
144 * @brief Pop the current error handler from the stack.
145 *
146 * @param reduct Pointer to the Reduct structure.
147 */
148REDUCT_API void reduct_error_pop(struct reduct* reduct);
149
150/**
151 * @brief Throw an error using the jump buffer in the error structure.
152 *
153 * @param _reduct Pointer to the Reduct structure.
154 * @param _error Pointer to the error structure.
155 * @param _item Pointer to the item that caused the error.
156 * @param _type The suffix of the error type (e.g., INTERNAL, RUNTIME, etc.).
157 * @param ... The error message format string and any optional arguments.
158 */
159#define REDUCT_ERROR_GENERIC(_reduct, _error, _item, _type, ...) \
160 do \
161 { \
162 const char* __path; \
163 const char* __input; \
164 size_t __inputLength; \
165 size_t __regionLength; \
166 size_t __position; \
167 reduct_error_get_item_params((_reduct), (_item), &__path, &__input, &__inputLength, &__regionLength, \
168 &__position); \
169 reduct_error_set((_error), __path, __input, __inputLength, __regionLength, __position, \
170 REDUCT_ERROR_TYPE_##_type, __VA_ARGS__); \
171 longjmp((_error)->jmp, true); \
172 } while (0)
173
174/**
175 * @brief Check if an error structure indicates a successful operation.
176 *
177 * @param _error Pointer to the error structure.
178 */
179#define REDUCT_ERROR_SUCCESS(_error) ((_error)->type == REDUCT_ERROR_TYPE_NONE)
180
181/**
182 * @brief Catch an error using the jump buffer in the error structure.
183 *
184 * @param _error Pointer to the error structure.
185 */
186#define REDUCT_ERROR_CATCH(_error) (setjmp((_error)->jmp))
187
188/**
189 * @brief Execute a block of code safely, catching any Reduct errors.
190 *
191 * @warning Do not use `return`, `break`, `continue`, or `goto` to exit the block, as it
192 * will skip the necessary error stack cleanup. Use a status variable instead.
193 *
194 * @param _reduct Pointer to the Reduct structure.
195 * @param _error Pointer to the error structure.
196 */
197#define REDUCT_ERROR_TRY(_reduct, _error) \
198 for (int _once = (reduct_error_push((_reduct), (_error)), 0); _once < 1; (reduct_error_pop(_reduct), _once++)) \
199 if (REDUCT_ERROR_CATCH(_error) == 0)
200
201/**
202 * @brief Throw a runtime error using the jump buffer in the error structure.
203 *
204 * @param _reduct Pointer to the Reduct structure.
205 * @param ... The error message format string and any optional arguments.
206 */
207#define REDUCT_ERROR_THROW(_reduct, ...) reduct_error_throw_runtime((_reduct), __VA_ARGS__)
208
209/**
210 * @brief Rethrow an existing error.
211 *
212 * @param _reduct Pointer to the Reduct structure.
213 * @param _error Pointer to the error structure.
214 */
215#define REDUCT_ERROR_RETHROW(_reduct, _error) REDUCT_ERROR_THROW(_reduct, "%s", (_error)->message);
216
217/**
218 * @brief Throw a runtime error if the expression is false.
219 *
220 * @param _reduct Pointer to the Reduct structure.
221 * @param _expr The expression to check.
222 * @param ... The error message format string and any optional arguments.
223 */
224#define REDUCT_ERROR_ASSERT(_reduct, _expr, ...) \
225 do \
226 { \
227 if (REDUCT_UNLIKELY(!(_expr))) \
228 { \
229 REDUCT_ERROR_THROW(_reduct, __VA_ARGS__); \
230 } \
231 } while (0)
232
233/**
234 * @brief Throw a syntax error using the jump buffer in the error structure.
235 *
236 * @param _error Pointer to the error structure.
237 * @param _input Pointer to the input structure being parsed.
238 * @param _ptr Pointer to the current position in the input buffer.
239 * @param ... The error message format string and any optional arguments.
240 */
241#define REDUCT_ERROR_SYNTAX(_error, _input, _ptr, ...) \
242 do \
243 { \
244 reduct_error_set((_error), (_input)->path, (_input)->buffer, (_input)->end - (_input)->buffer, 1, \
245 (size_t)((_ptr) - (_input)->buffer), REDUCT_ERROR_TYPE_SYNTAX, __VA_ARGS__); \
246 longjmp((_error)->jmp, true); \
247 } while (0)
248
249/**
250 * @brief Throw a compile error using the jump buffer in the error structure.
251 *
252 * @param _compiler The compiler instance.
253 * @param _handle Pointer to the handle that caused the error.
254 * @param ... The error message format string and any optional arguments.
255 */
256#define REDUCT_ERROR_COMPILE(_compiler, _handle, ...) \
257 do \
258 { \
259 struct reduct_item* __item = REDUCT_HANDLE_TO_ITEM(_handle); \
260 REDUCT_ERROR_GENERIC((_compiler)->reduct, (_compiler)->reduct->error, \
261 (((__item) != NULL && (__item)->inputId != REDUCT_INPUT_ID_NONE) \
262 ? (__item) \
263 : ((_compiler)->lastItem != NULL ? (_compiler)->lastItem : (__item))), \
264 COMPILE, __VA_ARGS__); \
265 } while (0)
266
267/**
268 * @brief Throw a compile error using the jump buffer in the error structure using the last item process by the
269 * compiler.
270 *
271 * @param _compiler The compiler instance.
272 * @param ... The error message format string and any optional arguments.
273 */
274#define REDUCT_ERROR_COMPILE_LAST(_compiler, ...) \
275 do \
276 { \
277 reduct_handle_t __handle = REDUCT_HANDLE_FROM_ITEM((_compiler)->lastItem); \
278 REDUCT_ERROR_COMPILE((_compiler), __handle, __VA_ARGS__); \
279 } while (0)
280
281/**
282 * @brief Throw a compile error if the expression is false.
283 *
284 * @param _compiler The compiler instance.
285 * @param _handle Pointer to the handle that caused the error.
286 * @param _expr The expression to check.
287 * @param ... The error message format string and any optional arguments.
288 */
289#define REDUCT_ERROR_COMPILE_ASSERT(_compiler, _expr, ...) \
290 do \
291 { \
292 if (REDUCT_UNLIKELY(!(_expr))) \
293 { \
294 reduct_handle_t __handle = REDUCT_HANDLE_FROM_ITEM((_compiler)->lastItem); \
295 REDUCT_ERROR_COMPILE((_compiler), __handle, __VA_ARGS__); \
296 } \
297 } while (0)
298
299/**
300 * @brief Throw an internal error using the jump buffer in the error structure.
301 *
302 * @param _reduct Pointer to the Reduct structure.
303 * @param ... The error message format string and any optional arguments.
304 */
305#define REDUCT_ERROR_INTERNAL(_reduct, ...) REDUCT_ERROR_GENERIC(_reduct, (_reduct)->error, NULL, INTERNAL, __VA_ARGS__)
306
307/** @} */
308
309#endif
#define REDUCT_NORETURN
Definition defs.h:60
uint16_t reduct_input_id_t
Identifies a reduct_input_t within a Reduct structure.
Definition defs.h:147
#define REDUCT_API
Definition defs.h:24
REDUCT_API void reduct_error_set(reduct_error_t *error, const char *path, const char *input, size_t inputLength, size_t regionLength, size_t position, reduct_error_type_t type, const char *message,...)
Set the error information in the error structure.
REDUCT_API REDUCT_NORETURN void reduct_error_throw_runtime(struct reduct *reduct, const char *message,...)
Throw a runtime error utilizing the evaluation state to determine the context.
REDUCT_API void reduct_error_push(struct reduct *reduct, reduct_error_t *error)
Push a new error handler onto the stack.
reduct_error_type_t
Error type enumeration.
Definition error.h:30
REDUCT_API void reduct_error_get_item_params(struct reduct *reduct, struct reduct_item *item, const char **path, const char **input, size_t *inputLength, size_t *regionLength, size_t *position)
Get the error parameters from a Reduct item.
REDUCT_API void reduct_error_get_row_column(reduct_error_t *error, size_t *row, size_t *column)
Get the row and column by traversing the input buffer.
REDUCT_API void reduct_error_print(reduct_error_t *error, FILE *file)
Format and print the error to a file.
REDUCT_API void reduct_error_pop(struct reduct *reduct)
Pop the current error handler from the stack.
#define REDUCT_ERROR_BACKTRACE_MAX
Maximum number of backtrace frames.
Definition error.h:23
#define REDUCT_ERROR_MAX_LEN
Maximum length of an error string.
Definition error.h:22
@ REDUCT_ERROR_TYPE_NONE
Definition error.h:31
@ REDUCT_ERROR_TYPE_SYNTAX
Definition error.h:32
@ REDUCT_ERROR_TYPE_RUNTIME
Definition error.h:34
@ REDUCT_ERROR_TYPE_INTERNAL
Definition error.h:35
@ REDUCT_ERROR_TYPE_COMPILE
Definition error.h:33
Backtrace frame structure.
Definition error.h:45
reduct_input_id_t inputId
The input ID of the source file.
Definition error.h:46
uint32_t position
The position in the input buffer.
Definition error.h:47
Error structure.
Definition error.h:55
reduct_error_type_t type
The type of the error.
Definition error.h:62
size_t index
The index of the region in the input buffer that caused the error.
Definition error.h:60
size_t regionLength
The length of the region that caused the error.
Definition error.h:59
const char * input
The input buffer.
Definition error.h:56
uint8_t frameCount
The number of backtrace frames.
Definition error.h:67
struct reduct_error * prev
Previous error handler in the stack.
Definition error.h:64
struct reduct * reduct
The owning Reduct structure.
Definition error.h:65
const char * path
The path to the file that caused the error.
Definition error.h:58
jmp_buf jmp
Definition error.h:61
size_t inputLength
The total length of the input buffer.
Definition error.h:57