Reduct  v1.0.4-3-gdaf0d70
A functional and immutable language.
Loading...
Searching...
No Matches
error_impl.h
Go to the documentation of this file.
1#ifndef REDUCT_ERROR_IMPL_H
2#define REDUCT_ERROR_IMPL_H 1
3
4#include "error.h"
5#include "eval.h"
6#include "item.h"
7
8static inline const char* reduct_error_type_str(reduct_error_type_t type)
9{
10 switch (type)
11 {
13 return "syntax error";
15 return "compile error";
17 return "runtime error";
19 return "internal error";
20 default:
21 return "error";
22 }
23}
24
25static inline reduct_size_t reduct_error_get_region_length(const char* ptr, const char* end)
26{
27 if (ptr >= end)
28 {
29 return 0;
30 }
31
32 if (*ptr == '(')
33 {
34 reduct_size_t depth = 0;
35 reduct_bool_t inString = REDUCT_FALSE;
36 const char* current = ptr;
37 while (current < end)
38 {
39 if (*current == '\\' && current + 1 < end)
40 {
41 current += 2;
42 continue;
43 }
44 if (*current == '"')
45 {
46 inString = !inString;
47 }
48 else if (!inString)
49 {
50 if (*current == '(')
51 {
52 depth++;
53 }
54 else if (*current == ')')
55 {
56 depth--;
57 if (depth == 0)
58 {
59 current++;
60 break;
61 }
62 }
63 }
64 current++;
65 }
66 return (reduct_size_t)(current - ptr);
67 }
68 else if (*ptr == '"')
69 {
70 const char* current = ptr + 1;
71 while (current < end)
72 {
73 if (*current == '\\' && current + 1 < end)
74 {
75 current += 2;
76 continue;
77 }
78 if (*current == '"')
79 {
80 current++;
81 break;
82 }
83 current++;
84 }
85 return (reduct_size_t)(current - ptr);
86 }
87 else
88 {
89 const char* current = ptr;
90 while (current < end && *current != ' ' && *current != '\t' && *current != '\n' && *current != '\r' &&
91 *current != '(' && *current != ')')
92 {
93 current++;
94 }
95 return (reduct_size_t)(current - ptr);
96 }
97}
98
100{
101 REDUCT_ASSERT(error != REDUCT_NULL);
102
103 reduct_size_t row;
104 reduct_size_t column;
105 reduct_error_get_row_column(error, &row, &column);
106
107 const char* typeStr = reduct_error_type_str(error->type);
108
109 if (error->path != REDUCT_NULL)
110 {
111 REDUCT_FPRINTF(file, "%s:%zu:%zu: %s: %s\n", error->path, row, column, typeStr, error->message);
112 }
113 else
114 {
115 REDUCT_FPRINTF(file, "%s: %s\n", typeStr, error->message);
116 }
117
118 if (error->input != REDUCT_NULL)
119 {
120 const char* lineStart = error->input + error->index;
121 while (lineStart > error->input && *(lineStart - 1) != '\n')
122 {
123 lineStart--;
124 }
125
126 const char* lineEnd = error->input + error->index;
127 while (lineEnd < error->input + error->inputLength && *lineEnd != '\n' && *lineEnd != '\r')
128 {
129 lineEnd++;
130 }
131
132 reduct_size_t lineLen = (reduct_size_t)(lineEnd - lineStart);
133 REDUCT_FPRINTF(file, " %4zu | %.*s\n", row, (int)lineLen, lineStart);
134 REDUCT_FPRINTF(file, " | ");
135
136 for (reduct_size_t i = 0; i < column - 1; i++)
137 {
138 REDUCT_FWRITE(" ", 1, 1, file);
139 }
140 reduct_size_t indicatorLen = error->regionLength > 0 ? error->regionLength : 1;
141 for (reduct_size_t i = 0; i < indicatorLen; i++)
142 {
143 REDUCT_FWRITE("^", 1, 1, file);
144 }
145 REDUCT_FWRITE("\n", 1, 1, file);
146 }
147 else
148 {
149 REDUCT_FWRITE("\n", 1, 1, file);
150 }
151}
152
154{
155 REDUCT_ASSERT(error != REDUCT_NULL);
157 REDUCT_ASSERT(column != REDUCT_NULL);
158
159 *row = 1;
160 *column = 1;
161
162 if (error->input == REDUCT_NULL)
163 {
164 return;
165 }
166
167 for (reduct_size_t i = 0; i < error->index; i++)
168 {
169 if (error->input[i] == '\n')
170 {
171 (*row)++;
172 *column = 1;
173 }
174 else
175 {
176 (*column)++;
177 }
178 }
179}
180
181REDUCT_API void reduct_error_set(reduct_error_t* error, const char* path, const char* input, reduct_size_t inputLength,
182 reduct_size_t regionLength, reduct_size_t position, reduct_error_type_t type, const char* message, ...)
183{
184 REDUCT_ASSERT(error != REDUCT_NULL);
185 REDUCT_ASSERT(message != REDUCT_NULL);
186
187 error->path = path;
188 error->input = input;
189 error->inputLength = inputLength;
190 error->regionLength = regionLength;
191 error->type = type;
192 error->index = position;
193
194 reduct_va_list args;
195 REDUCT_VA_START(args, message);
196 REDUCT_VSNPRINTF(error->message, REDUCT_ERROR_MAX_LEN, message, args);
197 REDUCT_VA_END(args);
198}
199
200REDUCT_API void reduct_error_get_item_params(struct reduct_item* item, const char** path, const char** input,
201 reduct_size_t* inputLength, reduct_size_t* regionLength, reduct_size_t* position)
202{
203 if (item != REDUCT_NULL && item->input != REDUCT_NULL)
204 {
205 *path = item->input->path;
206 *input = item->input->buffer;
207 *inputLength = item->input->end - item->input->buffer;
208 *regionLength = reduct_error_get_region_length(item->input->buffer + item->position, item->input->end);
209 if (*regionLength == 0)
210 {
211 *regionLength = 1;
212 }
213
214 *position = item->position;
215 }
216 else
217 {
218 *path = REDUCT_NULL;
219 *input = REDUCT_NULL;
220 *inputLength = 0;
221 *regionLength = 0;
222 *position = 0;
223 }
224}
225
226REDUCT_API void reduct_error_throw_runtime(struct reduct* reduct, const char* message, ...)
227{
228 const char* path = REDUCT_NULL;
229 const char* input = REDUCT_NULL;
230 reduct_size_t inputLength = 0;
231 reduct_size_t regionLength = 0;
232 reduct_size_t position = 0;
233
234 if (reduct->evalState != REDUCT_NULL && reduct->evalState->frameCount > 0)
235 {
236 reduct_eval_frame_t* frame = &reduct->evalState->frames[reduct->evalState->frameCount - 1];
237 if (frame->closure != REDUCT_NULL && frame->closure->function != REDUCT_NULL)
238 {
239 reduct_function_t* func = frame->closure->function;
240 reduct_size_t instIndex = frame->ip > func->insts ? (reduct_size_t)(frame->ip - func->insts - 1) : 0;
241 if (instIndex < func->instCount && func->positions != REDUCT_NULL)
242 {
243 position = func->positions[instIndex];
244 }
245
246 reduct_item_t* funcItem = REDUCT_CONTAINER_OF(func, reduct_item_t, function);
247 if (funcItem->input != REDUCT_NULL)
248 {
249 path = funcItem->input->path;
250 input = funcItem->input->buffer;
251 inputLength = (reduct_size_t)(funcItem->input->end - funcItem->input->buffer);
252 regionLength = reduct_error_get_region_length(input + position, funcItem->input->end);
253 if (regionLength == 0)
254 {
255 regionLength = 1;
256 }
257 }
258 }
259 }
260
261 reduct_va_list args;
262 REDUCT_VA_START(args, message);
263 char formattedMessage[REDUCT_ERROR_MAX_LEN];
264 REDUCT_VSNPRINTF(formattedMessage, REDUCT_ERROR_MAX_LEN, message, args);
265 REDUCT_VA_END(args);
266
267 reduct_error_set(reduct->error, path, input, inputLength, regionLength, position, REDUCT_ERROR_TYPE_RUNTIME, "%s",
268 formattedMessage);
269 REDUCT_LONGJMP(reduct->error->jmp, REDUCT_TRUE);
270}
271
272REDUCT_API void reduct_error_check_arity(reduct_t* reduct, reduct_size_t argc, reduct_size_t expected, const char* name)
273{
274 if (REDUCT_UNLIKELY(argc != expected))
275 {
276 REDUCT_ERROR_RUNTIME(reduct, "%s expects exactly %zu argument(s), got %zu", name, expected,
277 (reduct_size_t)argc);
278 }
279}
280
282{
283 if (REDUCT_UNLIKELY(argc < min))
284 {
285 REDUCT_ERROR_RUNTIME(reduct, "%s expects at least %zu argument(s), got %zu", name, (reduct_size_t)min,
286 (reduct_size_t)argc);
287 }
288}
289
291 reduct_size_t max, const char* name)
292{
293 if (REDUCT_UNLIKELY(argc < min || argc > max))
294 {
295 REDUCT_ERROR_RUNTIME(reduct, "%s expects between %zu and %zu argument(s), got %zu", name, (reduct_size_t)min,
296 (reduct_size_t)max, (reduct_size_t)argc);
297 }
298}
299
300#endif
#define REDUCT_VSNPRINTF
Definition defs.h:52
size_t reduct_size_t
Definition defs.h:100
#define REDUCT_VA_END(_ap)
Definition defs.h:88
va_list reduct_va_list
Definition defs.h:90
#define REDUCT_UNLIKELY(_x)
Definition defs.h:118
#define REDUCT_FPRINTF
Definition defs.h:50
reduct_bool_t
Boolean type.
Definition defs.h:135
@ REDUCT_FALSE
Definition defs.h:137
@ REDUCT_TRUE
Definition defs.h:136
#define REDUCT_FWRITE(_ptr, _size, _nmemb, _file)
Definition defs.h:48
#define REDUCT_CONTAINER_OF(_ptr, _type, _member)
Container of macro.
Definition defs.h:184
#define REDUCT_LONGJMP(_env, _val)
Definition defs.h:42
FILE * reduct_file_t
Definition defs.h:44
#define REDUCT_ASSERT(_cond)
Definition defs.h:25
#define REDUCT_VA_START(_ap, _last)
Definition defs.h:87
#define REDUCT_API
Definition defs.h:7
#define REDUCT_NULL
Definition defs.h:23
Error handling and reporting.
REDUCT_API void reduct_error_check_arity_range(reduct_t *reduct, reduct_size_t argc, reduct_size_t min, reduct_size_t max, const char *name)
Definition error_impl.h:290
REDUCT_API void reduct_error_check_arity(reduct_t *reduct, reduct_size_t argc, reduct_size_t expected, const char *name)
Definition error_impl.h:272
REDUCT_API void reduct_error_check_min_arity(reduct_t *reduct, reduct_size_t argc, reduct_size_t min, const char *name)
Definition error_impl.h:281
static const char * reduct_error_type_str(reduct_error_type_t type)
Definition error_impl.h:8
static reduct_size_t reduct_error_get_region_length(const char *ptr, const char *end)
Definition error_impl.h:25
Virtual machine evaluation.
REDUCT_API void reduct_error_print(reduct_error_t *error, reduct_file_t file)
Format and print the error to a file.
Definition error_impl.h:99
#define REDUCT_ERROR_RUNTIME(_reduct,...)
Throw a runtime error using the jump buffer in the error structure.
Definition error.h:175
REDUCT_API void reduct_error_throw_runtime(struct reduct *reduct, const char *message,...)
Throw a runtime error utilizing the evaluation state to determine the context.
Definition error_impl.h:226
REDUCT_API void reduct_error_get_item_params(struct reduct_item *item, const char **path, const char **input, reduct_size_t *inputLength, reduct_size_t *regionLength, reduct_size_t *position)
Get the error parameters from a Reduct item.
Definition error_impl.h:200
REDUCT_API void reduct_error_get_row_column(reduct_error_t *error, reduct_size_t *row, reduct_size_t *column)
Get the row and column by traversing the input buffer.
Definition error_impl.h:153
reduct_error_type_t
Error type enumeration.
Definition error.h:24
REDUCT_API void reduct_error_set(reduct_error_t *error, const char *path, const char *input, reduct_size_t inputLength, reduct_size_t regionLength, reduct_size_t position, reduct_error_type_t type, const char *message,...)
Set the error information in the error structure.
Definition error_impl.h:181
#define REDUCT_ERROR_MAX_LEN
Maximum length of an error string.
Definition error.h:17
@ REDUCT_ERROR_TYPE_SYNTAX
Definition error.h:26
@ REDUCT_ERROR_TYPE_RUNTIME
Definition error.h:28
@ REDUCT_ERROR_TYPE_INTERNAL
Definition error.h:29
@ REDUCT_ERROR_TYPE_COMPILE
Definition error.h:27
Item management.
Error structure.
Definition error.h:37
reduct_error_type_t type
The type of the error.
Definition error.h:44
char message[REDUCT_ERROR_MAX_LEN]
Definition error.h:45
reduct_size_t index
The index of the region in the input buffer that caused the error.
Definition error.h:42
const char * input
The input buffer.
Definition error.h:38
const char * path
THe path to the file that caused the error.
Definition error.h:40
reduct_size_t inputLength
The total length of the input buffer.
Definition error.h:39
reduct_size_t regionLength
The length of the region that caused the error.
Definition error.h:41
Evaluation frame structure.
Definition eval.h:29
struct reduct_closure * closure
The closure being evaluated.
Definition eval.h:30
reduct_inst_t * ip
The current instruction pointer.
Definition eval.h:31
Compiled function structure.
Definition function.h:78
reduct_inst_t * insts
An array of instructions.
Definition function.h:81
reduct_uint32_t * positions
An array of source positions parallel to the instructions.
Definition function.h:82
Item structure.
Definition item.h:57
struct reduct_input * input
The parsed input that created this item.
Definition item.h:58
State structure.
Definition core.h:61