/
solerror.h
105 lines (77 loc) · 3.83 KB
/
solerror.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#ifndef SOLERROR_H
#define SOLERROR_H
#include <stdlib.h>
#include <stdarg.h>
#include <setjmp.h>
#include <stdbool.h>
/* try, catch, finally */
#define SOL_TRY \
for (int _sol_error_jmp_code = -1; _sol_error_jmp_code == -1;) \
if ((_sol_error_jmp_code = setjmp(_sol_error_try_frames[++_sol_error_try_frame_top])) == 0) \
for (; 1; longjmp(_sol_error_try_frames[_sol_error_try_frame_top], -1))
#define SOL_CATCH(type, err) \
else if (sol_error_get_current_error() && sol_error_extends_type(sol_error_get_current_error(), &(type))) \
for (sol_error* (err) = sol_error_get_current_error(); (err) != NULL; \
sol_error_free_current_error(), (err) = NULL, longjmp(_sol_error_try_frames[_sol_error_try_frame_top], -1))
#define SOL_FINALLY \
else for (int _sol_error_run_once = 1; _sol_error_run_once; \
_sol_error_run_once = 0, \
(_sol_error_jmp_code != -1 \
? rethrow() \
: --_sol_error_try_frame_top), \
_sol_error_jmp_code = 0)
#define SOL_THROW(err) \
sol_error_throw_error((err))
#define SOL_THROW_MESSAGE(type, format, ...) \
throw (sol_error_create(&(type), (format), ##__VA_ARGS__))
#define SOL_RETHROW() \
sol_error_rethrow_current_error()
#define try SOL_TRY
#define catch(type, err) SOL_CATCH(type, err)
#define finally SOL_FINALLY
#define throw(err) SOL_THROW(err)
#define throw_msg(type, format, ...) SOL_THROW_MESSAGE(type, format, ##__VA_ARGS__)
#define rethrow() SOL_RETHROW()
/* exception type declarations */
typedef struct sol_error_type {
struct sol_error_type* parent;
char* name;
int error_code;
} sol_error_type;
typedef struct sol_error {
sol_error_type* type;
char* message;
void* data;
} sol_error;
#define SOL_ERROR_DECLARE(name) extern sol_error_type (name)
#define SOL_ERROR_DEFINE(name, super) sol_error_type (name) = {(super), #name, __COUNTER__ + 1}
/* globals */
extern int _sol_error_try_frame_top;
extern jmp_buf _sol_error_try_frames[];
/* functions */
sol_error* sol_error_create(sol_error_type* type, char* format, ...);
void sol_error_free(sol_error* error);
void sol_error_throw_error(sol_error* error);
sol_error* sol_error_get_current_error();
void sol_error_rethrow_current_error();
void sol_error_free_current_error();
bool sol_error_extends_type(sol_error* error, sol_error_type* type);
bool sol_error_type_extends_type(sol_error_type* error_type, sol_error_type* type);
/* error types */
SOL_ERROR_DECLARE(Error);
SOL_ERROR_DECLARE(BoundsError);
SOL_ERROR_DECLARE(BytecodeError);
SOL_ERROR_DECLARE(TypeError);
/* helper macros */
#define SOL_THROW_MISSING_ARGUMENT(name) \
throw_msg (Error, "missing argument '%s'", (name))
#define SOL_REQUIRE_BOUNDS(index, min, max) \
if ((index) < min || (index) > max) \
for (; 1; throw_msg (BoundsError, "index '%i' was out of bounds [%i, %i]", (index), (min), (max)))
#define SOL_REQUIRE_TYPE(obj, type) \
if (!(obj) || ((SolObject) obj)->type_id != (type)) \
for (; 1; throw_msg (TypeError, "expected %s, found %s", sol_type_string((type)), sol_obj_type_string((SolObject) (obj))))
#define SOL_REQUIRE_DATATYPE(obj, type) \
if (!(obj) || ((SolObject) obj)->type_id != TYPE_SOL_DATATYPE || ((SolDatatype) (obj))->type_id != (type)) \
for (; 1; throw_msg (TypeError, "expected %s, found %s", sol_datatype_string((type)), sol_obj_type_string((SolObject) (obj))))
#endif