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