1#include "include/pw.h"
2
3void _pw_set_exception(PwValuePtr status, uint16_t type_id, PwCtorArgs* ctor_args, char* message, ...)
4{
5 PwValue parent = PW_NULL;
6 pw_move(&parent, ¤t_task->status);
7
8 PwExceptionCtorArgs args = {
9 .next = ctor_args,
10 .type_id = PwTypeId_Exception,
11 .status = status,
12 .parent_exc = &parent,
13 .message = message
14 };
15 va_start(args.ap);
16 PwValue exc = PW_NULL;
17 if (!pw_create2(type_id, &args, &exc)) {
18 pw_move(&exc, &parent);
19 }
20 va_end(args.ap);
21 pw_move(¤t_task->status, &exc);
22}
23
24[[nodiscard]] bool pw_is_error(PwValuePtr value)
25{
26 if (pw_is_status(value)) {
27 return (bool) value->status_code;
28 } else if (pw_is_exception(value)) {
29 return true;
30 } else {
31 return false;
32 }
33}
34
35[[nodiscard]] bool pw_is_eof(PwValuePtr status)
36{
37 if (pw_is_exception(status)) {
38 _PwExceptionData* exc = _pw_get_struct_ptr(status, PwTypeId_Exception);
39 status = &exc->status;
40 }
41 if (!pw_is_status(status)) {
42 return false;
43 }
44 return status->kind == PwStatusKind_Basic && status->status_code == PweEOF;
45}
46
47[[nodiscard]] bool pw_is_errno(PwValuePtr status, int _errno)
48{
49 if (pw_is_exception(status)) {
50 _PwExceptionData* exc = _pw_get_struct_ptr(status, PwTypeId_Exception);
51 status = &exc->status;
52 }
53 if (!pw_is_status(status)) {
54 return false;
55 }
56 return status->kind == PwStatusKind_Errno && status->pw_errno == _errno;
57}
58
59/****************************************************************
60 * Basic interface methods
61 */
62
63static bool exception_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
64{
65 // do not pass ctor_args to the super method which in particular is Status constructor;
66 // Status is a mixin but it's not a subtype of Struct, and initializing the result as Status
67 // is not what we want
68 if (!pw_super(mthis, result, nullptr)) {
69 return false;
70 }
71 _PwExceptionData* exc = pw_this_data(result);
72
73 PwExceptionCtorArgs* args = pw_this_ctor_args();
74 if (args) {
75 if (!pw_vsprintf(&exc->message, args->message, args->ap)) {
76 return false;
77 }
78 pw_move(&exc->status, args->status);
79 if (args->parent_exc) {
80 pw_move(&exc->parent_exc, args->parent_exc);
81 }
82 }
83 return true;
84}
85
86static bool exception_destroy(PwMethod_Basic_destroy* mthis, PwValuePtr self, _PwCompoundChain* tail)
87{
88 PwValuePtr value_seen = _pw_on_chain(self, tail);
89 if (value_seen) {
90 return true;
91 }
92 _PwExceptionData* exc = pw_this_data(self);
93 pw_destroy(&exc->status);
94 pw_destroy(&exc->message);
95 pw_destroy(&exc->parent_exc);
96 return pw_super(mthis, self, tail);
97}
98
99static bool exception_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
100{
101 _pw_hash_uint64(ctx, self->type_id);
102 _PwExceptionData* exc = pw_this_data(self);
103 _pw_call_hash(&exc->status, ctx, tail);
104 _pw_call_hash(&exc->message, ctx, tail);
105 _pw_call_hash(&exc->parent_exc, ctx, tail);
106 return true;
107}
108
109static bool exception_deepcopy(PwMethod_Basic_deepcopy* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
110{
111 if (!pw_create(self->type_id, result)) {
112 return false;
113 }
114 _PwExceptionData* src_exc = pw_this_data(self);
115 _PwExceptionData* dest_exc = pw_this_data(result);
116
117 if (!pw_deepcopy(&dest_exc->status, &src_exc->status)) {
118 goto err;
119 }
120 if (!pw_deepcopy(&dest_exc->message, &src_exc->message)) {
121 goto err;
122 }
123 if (!pw_deepcopy(&dest_exc->parent_exc, &src_exc->parent_exc)) {
124 goto err;
125 }
126 return true;
127err:
128 pw_destroy(result);
129 return false;
130}
131
132static bool exception_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
133{
134 pw_destroy(result);
135 *result = PwString("Exception: ");
136 _PwExceptionData* exc = _pw_get_struct_ptr(self, PwTypeId_Exception);
137 if (!pw_string_append(result, &exc->message)) {
138 return false;
139 }
140 if (!pw_string_append(result, U'\n')) {
141 return false;
142 }
143 PwValue s = PW_NULL;
144 if (!pw_to_string(&exc->status, &s)) {
145 return false;
146 }
147 if (! pw_string_append(result, &s)) {
148 return false;
149 }
150 if (!pw_string_append(result, U'\n')) {
151 return false;
152 }
153 if (!pw_is_null(&exc->parent_exc)) {
154 if (!pw_to_string(&exc->parent_exc, &s)) {
155 return false;
156 }
157 if (!pw_string_append(result, &s)) {
158 return false;
159 }
160 }
161 return true;
162}
163
164static bool exception_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
165{
166 if (!pw_super(mthis, self, fp, indent, tail)) {
167 return false;
168 }
169
170 _PwExceptionData* exc = pw_this_data(self);
171
172 _pw_print_indent(fp, indent);
173 fprintf(fp, "Exception: %p\n", (void*) exc);
174 if (!_pw_call_dump(fp, &exc->message, indent + 4, tail)) {
175 return false;
176 }
177 if (!_pw_call_dump(fp, &exc->status, indent + 4, tail)) {
178 return false;
179 }
180 if (!pw_is_null(&exc->parent_exc)) {
181 return _pw_call_dump(fp, &exc->parent_exc, indent + 4, tail);
182 }
183 return true;
184}
185
186static bool exception_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
187{
188 if (other->type_id != PwTypeId_Exception) {
189 return false;
190 }
191 _PwExceptionData* this_exc = pw_this_data(self);
192 _PwExceptionData* other_exc = pw_this_data(other); // okay to use _pw_this_data because types match
193 return pw_equal(&this_exc->status, &other_exc->status);
194}
195
196static bool exception_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
197{
198 return true;
199}
200
201#define exception_clone nullptr
202#define exception_decref nullptr
203#define exception_is_immutable nullptr
204#define exception_iter_children nullptr
205
206PwInterface_Basic _pw_exception_basic_interface = {
207#define X(name, ...) .name = { .func = exception_##name } __VA_OPT__(,)
208 PW_BASIC_INTERFACE_METHODS
209#undef X
210};