Reduct  v1.0.4-3-gdaf0d70
A functional and immutable language.
Loading...
Searching...
No Matches
parse_impl.h
Go to the documentation of this file.
1#ifndef REDUCT_PARSE_IMPL_H
2#define REDUCT_PARSE_IMPL_H 1
3
4#include "atom.h"
5#include "char.h"
6#include "core.h"
7#include "error.h"
8#include "gc.h"
9#include "item.h"
10#include "list.h"
11#include "parse.h"
12
13#define REDUCT_PARSE_STACK_MAX 256
14
23
37
39{
40 if (!REDUCT_HANDLE_IS_ITEM(&handle))
41 {
43 }
44 reduct_item_t* item = REDUCT_HANDLE_TO_ITEM(&handle);
45 if (item->type != REDUCT_ITEM_TYPE_ATOM)
46 {
48 }
49 reduct_atom_t* atom = &item->atom;
50
51 if (unary)
52 {
53 if (reduct_atom_is_equal(atom, "not", 3) || reduct_atom_is_equal(atom, "-", 1))
54 {
56 }
58 }
59
60 if (reduct_atom_is_equal(atom, "or", 2))
61 {
63 }
64 if (reduct_atom_is_equal(atom, "and", 3))
65 {
67 }
68 if (reduct_atom_is_equal(atom, "==", 2) || reduct_atom_is_equal(atom, "!=", 2) ||
69 reduct_atom_is_equal(atom, "<", 1) || reduct_atom_is_equal(atom, "<=", 2) ||
70 reduct_atom_is_equal(atom, ">", 1) || reduct_atom_is_equal(atom, ">=", 2))
71 {
73 }
74 if (reduct_atom_is_equal(atom, "<<", 2) || reduct_atom_is_equal(atom, ">>", 2))
75 {
77 }
78 if (reduct_atom_is_equal(atom, "&", 1) || reduct_atom_is_equal(atom, "|", 1) || reduct_atom_is_equal(atom, "^", 1))
79 {
81 }
82 if (reduct_atom_is_equal(atom, "*", 1) || reduct_atom_is_equal(atom, "/", 1) || reduct_atom_is_equal(atom, "%", 1))
83 {
85 }
86 if (reduct_atom_is_equal(atom, "+", 1) || reduct_atom_is_equal(atom, "-", 1))
87 {
89 }
90
92}
93
95 reduct_parse_precedence_t minPrecedence)
96{
97 if (*pos >= list->length)
98 {
99 return reduct_handle_nil(reduct);
100 }
101
102 reduct_handle_t first = reduct_list_nth(reduct, list, *pos);
103 reduct_handle_t left;
105
106 if (unaryPrecedence > REDUCT_PARSE_PRECEDENCE_NONE)
107 {
108 (*pos)++;
109 reduct_handle_t operand = reduct_parse_infix_transform_recursive(reduct, list, pos, unaryPrecedence);
110 reduct_list_t* call = reduct_list_new(reduct);
111 reduct_list_append(reduct, call, first);
112 reduct_list_append(reduct, call, operand);
114 }
115 else
116 {
117 left = first;
118 (*pos)++;
119 }
120
121 while (*pos < list->length)
122 {
123 reduct_handle_t op = reduct_list_nth(reduct, list, *pos);
125 if (prec == REDUCT_PARSE_PRECEDENCE_NONE || prec < minPrecedence)
126 {
127 break;
128 }
129
130 (*pos)++;
131 if (*pos >= list->length)
132 {
133 break;
134 }
135
136 reduct_handle_t right = reduct_parse_infix_transform_recursive(reduct, list, pos, prec + 1);
137
138 reduct_list_t* call = reduct_list_new(reduct);
139 reduct_list_append(reduct, call, op);
140 reduct_list_append(reduct, call, left);
141 reduct_list_append(reduct, call, right);
143 }
144
145 return left;
146}
147
149{
150 if (list->length == 0)
151 {
152 return reduct_handle_nil(reduct);
153 }
154
155 reduct_size_t pos = 0;
157}
158
160{
162
163 while (ctx->ptr < ctx->input->end)
164 {
166 {
167 ctx->ptr++;
168 }
169 else if (*ctx->ptr == '/' && ctx->ptr + 1 < ctx->input->end && *(ctx->ptr + 1) == '/')
170 {
171 while (ctx->ptr < ctx->input->end && *ctx->ptr != '\n')
172 {
173 ctx->ptr++;
174 }
175 }
176 else if (*ctx->ptr == '/' && ctx->ptr + 1 < ctx->input->end && *(ctx->ptr + 1) == '*')
177 {
178 ctx->ptr += 2;
179 while (ctx->ptr < ctx->input->end)
180 {
181 if (*ctx->ptr == '*' && ctx->ptr + 1 < ctx->input->end && *(ctx->ptr + 1) == '/')
182 {
183 ctx->ptr += 2;
184 break;
185 }
186 ctx->ptr++;
187 }
188 }
189 else
190 {
191 break;
192 }
193 }
194}
195
197{
198 REDUCT_ASSERT(reduct != REDUCT_NULL);
200
201 ctx->ptr++;
202 const char* start = ctx->ptr;
203 while (ctx->ptr < ctx->input->end)
204 {
205 if (*ctx->ptr == '\\' && ctx->ptr + 1 < ctx->input->end)
206 {
207 ctx->ptr += 2;
208 }
209 else if (*ctx->ptr == '"')
210 {
211 break;
212 }
213 else
214 {
215 ctx->ptr++;
216 }
217 }
218
219 if (ctx->ptr >= ctx->input->end)
220 {
221 REDUCT_ERROR_SYNTAX(reduct->error, ctx->input, start, "unexpected end of file, missing '\"'");
222 }
223
224 reduct_size_t len = (reduct_size_t)(ctx->ptr - start);
226
228 item->input = ctx->input;
229 item->position = (reduct_size_t)(start - ctx->input->buffer);
231
232 reduct_atom_normalize(reduct, atom);
233
234 reduct_list_append(reduct, ctx->stack[ctx->current], REDUCT_HANDLE_FROM_ITEM(item));
235 ctx->ptr++;
236}
237
239{
240 REDUCT_ASSERT(reduct != REDUCT_NULL);
242
243 const char* start = ctx->ptr;
244 while (ctx->ptr < ctx->input->end && !REDUCT_CHAR_IS_WHITESPACE(*ctx->ptr) && *ctx->ptr != '(' &&
245 *ctx->ptr != ')' && *ctx->ptr != '{' && *ctx->ptr != '}')
246 {
247 ctx->ptr++;
248 }
249
250 reduct_size_t len = (reduct_size_t)(ctx->ptr - start);
251 if (len == 0)
252 {
253 return;
254 }
255
256 reduct_atom_t* atom = reduct_atom_lookup(reduct, start, len, REDUCT_ATOM_LOOKUP_NONE);
258 item->input = ctx->input;
259 item->position = (reduct_size_t)(start - ctx->input->buffer);
260
261 reduct_atom_normalize(reduct, atom);
262
263 reduct_list_append(reduct, ctx->stack[ctx->current], REDUCT_HANDLE_FROM_ITEM(item));
264}
265
267{
268 reduct_list_t* root = reduct_list_new(reduct);
269 if (root == REDUCT_NULL)
270 {
271 REDUCT_ERROR_INTERNAL(reduct, "out of memory");
272 }
273
274 reduct_item_t* rootItem = REDUCT_CONTAINER_OF(root, reduct_item_t, list);
275 rootItem->input = input;
276 reduct_handle_t result = REDUCT_HANDLE_FROM_ITEM(rootItem);
277 REDUCT_GC_RETAIN(reduct, result);
278
280 ctx.ptr = input->buffer;
281 ctx.input = input;
282 ctx.current = 0;
283 ctx.stack[0] = root;
284 ctx.isInfix[0] = REDUCT_FALSE;
285
286 while (1)
287 {
289
290 if (ctx.ptr >= ctx.input->end)
291 {
292 break;
293 }
294
295 switch (*ctx.ptr)
296 {
297 case '{':
298 case '(':
299 {
300 if (ctx.current + 1 >= REDUCT_PARSE_STACK_MAX)
301 {
302 REDUCT_ERROR_SYNTAX(reduct->error, input, ctx.ptr, "maximum nesting depth exceeded");
303 }
304
305 reduct_list_t* child = reduct_list_new(reduct);
306 reduct_item_t* item = REDUCT_CONTAINER_OF(child, reduct_item_t, list);
307 item->input = input;
308 item->position = (reduct_size_t)(ctx.ptr - input->buffer) + 1;
309
310 ctx.current++;
311 ctx.stack[ctx.current] = child;
312 ctx.isInfix[ctx.current] = (*ctx.ptr == '{');
313 ctx.ptr++;
314 }
315 break;
316 case '}':
317 case ')':
318 {
319 if (ctx.current == 0)
320 {
321 REDUCT_ERROR_SYNTAX(reduct->error, input, ctx.ptr, "unexpected ')'");
322 }
323
324 if ((*ctx.ptr == ')' && ctx.isInfix[ctx.current]) || (*ctx.ptr == '}' && !ctx.isInfix[ctx.current]))
325 {
326 REDUCT_ERROR_SYNTAX(reduct->error, input, ctx.ptr, "mismatched parentheses");
327 }
328
329 reduct_list_t* child = ctx.stack[ctx.current];
330 reduct_bool_t childIsInfix = ctx.isInfix[ctx.current];
331
332 ctx.current--;
333 ctx.ptr++;
334
335 if (childIsInfix)
336 {
337 reduct_handle_t transformed = reduct_parse_infix_transform(reduct, child);
338 reduct_list_append(reduct, ctx.stack[ctx.current], transformed);
339 }
340 else
341 {
343 }
344 }
345 break;
346 default:
347 {
348 if (*ctx.ptr == '"')
349 {
350 reduct_parse_quoted_atom(reduct, &ctx);
351 }
352 else
353 {
354 reduct_parse_unquoted_atom(reduct, &ctx);
355 }
356 }
357 break;
358 }
359 }
360
361 if (ctx.current > 0)
362 {
363 REDUCT_ERROR_SYNTAX(reduct->error, ctx.input, ctx.ptr, "unexpected end of file, missing ')'");
364 }
365
366 return result;
367}
368
369REDUCT_API reduct_handle_t reduct_parse(reduct_t* reduct, const char* str, reduct_size_t len, const char* path)
370{
371 REDUCT_ASSERT(reduct != REDUCT_NULL);
373
374 if (reduct == REDUCT_NULL || str == REDUCT_NULL)
375 {
376 REDUCT_ERROR_INTERNAL(reduct, "invalid arguments");
377 }
378
379 reduct_input_t* input = reduct_input_new(reduct, str, len, path, REDUCT_INPUT_FLAG_NONE);
380 if (input == REDUCT_NULL)
381 {
382 REDUCT_ERROR_INTERNAL(reduct, "out of memory");
383 }
384
385 return reduct_parse_input(reduct, input);
386}
387
389{
390 REDUCT_ASSERT(reduct != REDUCT_NULL);
391 REDUCT_ASSERT(path != REDUCT_NULL);
392
393 reduct_file_t file = REDUCT_FOPEN(path, "rb");
394 if (file == REDUCT_NULL)
395 {
396 REDUCT_ERROR_INTERNAL(reduct, "could not open file '%s'", path);
397 }
398
399 fseek(file, 0, SEEK_END);
400 reduct_size_t len = (reduct_size_t)ftell(file);
401 fseek(file, 0, SEEK_SET);
402
403 if (len == (reduct_size_t)-1)
404 {
405 REDUCT_FCLOSE(file);
406 REDUCT_ERROR_INTERNAL(reduct, "could not read file '%s'", path);
407 }
408
409 reduct_size_t allocLen = len == 0 ? 1 : len;
410 char* buffer = REDUCT_MALLOC(allocLen);
411 if (buffer == REDUCT_NULL)
412 {
413 REDUCT_FCLOSE(file);
414 REDUCT_ERROR_INTERNAL(reduct, "out of memory");
415 }
416
417 if (len > 0 && REDUCT_FREAD(buffer, 1, len, file) != len)
418 {
419 REDUCT_FREE(buffer);
420 REDUCT_FCLOSE(file);
421 REDUCT_ERROR_INTERNAL(reduct, "could not read file '%s'", path);
422 }
423 REDUCT_FCLOSE(file);
424
425 reduct_input_t* input = reduct_input_new(reduct, buffer, len, path, REDUCT_INPUT_FLAG_OWNED);
426 if (input == REDUCT_NULL)
427 {
428 REDUCT_FREE(buffer);
429 REDUCT_ERROR_INTERNAL(reduct, "out of memory");
430 }
431
432 return reduct_parse_input(reduct, input);
433}
434
435#endif
Atom representation and operations.
Character handling.
Core definitions and structures.
#define REDUCT_MALLOC(_size)
Definition defs.h:27
size_t reduct_size_t
Definition defs.h:100
reduct_bool_t
Boolean type.
Definition defs.h:135
@ REDUCT_FALSE
Definition defs.h:137
@ REDUCT_TRUE
Definition defs.h:136
#define REDUCT_FCLOSE(_file)
Definition defs.h:46
#define REDUCT_CONTAINER_OF(_ptr, _type, _member)
Container of macro.
Definition defs.h:184
#define REDUCT_FOPEN(_path, _mode)
Definition defs.h:45
reduct_uint64_t reduct_handle_t
Handle type.
Definition defs.h:189
FILE * reduct_file_t
Definition defs.h:44
#define REDUCT_FREAD(_ptr, _size, _nmemb, _file)
Definition defs.h:47
#define REDUCT_ASSERT(_cond)
Definition defs.h:25
#define REDUCT_FREE(_ptr)
Definition defs.h:30
#define REDUCT_API
Definition defs.h:7
#define REDUCT_NULL
Definition defs.h:23
Error handling and reporting.
Garbage collection.
REDUCT_API reduct_atom_t * reduct_atom_lookup(struct reduct *reduct, const char *str, reduct_size_t len, reduct_atom_lookup_flags_t flags)
Lookup an atom in the Reduct structure.
static REDUCT_ALWAYS_INLINE reduct_bool_t reduct_atom_is_equal(reduct_atom_t *atom, const char *str, reduct_size_t len)
Check if an atom is equal to a string.
Definition atom.h:112
REDUCT_API void reduct_atom_normalize(struct reduct *reduct, reduct_atom_t *atom)
Normalize an atom, determining its shape and parsing escape sequences.
@ REDUCT_ATOM_LOOKUP_NONE
No flags.
Definition atom.h:39
@ REDUCT_ATOM_LOOKUP_QUOTED
Atom should be explicitly quoted.
Definition atom.h:40
#define REDUCT_CHAR_IS_WHITESPACE(_c)
Check if a character is whitespace.
Definition char.h:78
REDUCT_API reduct_input_t * reduct_input_new(reduct_t *reduct, const char *buffer, reduct_size_t length, const char *path, reduct_input_flags_t flags)
Create a new input structure and push it onto the input stack.
Definition core_impl.h:123
@ REDUCT_INPUT_FLAG_NONE
Definition core.h:29
@ REDUCT_INPUT_FLAG_OWNED
The input buffer is owned by the input structure and should be freed.
Definition core.h:30
#define REDUCT_ERROR_SYNTAX(_error, _input, _ptr,...)
Throw a syntax error using the jump buffer in the error structure.
Definition error.h:147
#define REDUCT_ERROR_INTERNAL(_reduct,...)
Throw an internal error using the jump buffer in the error structure.
Definition error.h:183
#define REDUCT_GC_RETAIN(_reduct, _handle)
Retain an item, preventing it from being collected by the GC.
Definition gc.h:38
#define REDUCT_HANDLE_IS_ITEM(_handle)
Check if a handle is an item.
Definition handle.h:171
#define REDUCT_HANDLE_FROM_LIST(_list)
Create a handle from a list pointer.
Definition handle.h:93
#define REDUCT_HANDLE_TO_ITEM(_handle)
Get the item pointer of a handle.
Definition handle.h:257
REDUCT_API reduct_handle_t reduct_handle_nil(struct reduct *reduct)
Get the constant nil handle.
#define REDUCT_HANDLE_FROM_ITEM(_ptr)
Create a handle from an item pointer.
Definition handle.h:76
#define REDUCT_ITEM_TYPE_ATOM
An atom.
Definition item.h:27
#define REDUCT_ITEM_FLAG_QUOTED
Item is a quoted atom.
Definition item.h:43
REDUCT_API reduct_handle_t reduct_parse_file(reduct_t *reduct, const char *path)
Parse a Reduct file.
Definition parse_impl.h:388
REDUCT_API reduct_handle_t reduct_parse(reduct_t *reduct, const char *str, reduct_size_t len, const char *path)
Parse a Reduct string.
Definition parse_impl.h:369
Item management.
List management.
REDUCT_API reduct_handle_t reduct_list_nth(struct reduct *reduct, reduct_list_t *list, reduct_size_t index)
Get the nth element of the list.
Definition list_impl.h:157
REDUCT_API void reduct_list_append(struct reduct *reduct, reduct_list_t *list, reduct_handle_t val)
Append an element to the list.
REDUCT_API reduct_list_t * reduct_list_new(struct reduct *reduct)
Create a new editable list.
Parser.
static reduct_parse_precedence_t reduct_parse_get_precedence(reduct_handle_t handle, reduct_bool_t unary)
Definition parse_impl.h:38
static void reduct_parse_quoted_atom(reduct_t *reduct, reduct_parse_ctx_t *ctx)
Definition parse_impl.h:196
static void reduct_parse_unquoted_atom(reduct_t *reduct, reduct_parse_ctx_t *ctx)
Definition parse_impl.h:238
#define REDUCT_PARSE_STACK_MAX
Definition parse_impl.h:13
static reduct_handle_t reduct_parse_infix_transform(reduct_t *reduct, reduct_list_t *list)
Definition parse_impl.h:148
static void reduct_parse_whitespace(reduct_parse_ctx_t *ctx)
Definition parse_impl.h:159
static reduct_handle_t reduct_parse_infix_transform_recursive(reduct_t *reduct, reduct_list_t *list, reduct_size_t *pos, reduct_parse_precedence_t minPrecedence)
Definition parse_impl.h:94
REDUCT_API reduct_handle_t reduct_parse_input(reduct_t *reduct, reduct_input_t *input)
Definition parse_impl.h:266
reduct_parse_precedence_t
Definition parse_impl.h:25
@ REDUCT_PARSE_PRECEDENCE_MAX
Definition parse_impl.h:35
@ REDUCT_PARSE_PRECEDENCE_NONE
Definition parse_impl.h:26
@ REDUCT_PARSE_PRECEDENCE_SHIFT
Definition parse_impl.h:30
@ REDUCT_PARSE_PRECEDENCE_UNARY
Definition parse_impl.h:34
@ REDUCT_PARSE_PRECEDENCE_BITWISE
Definition parse_impl.h:31
@ REDUCT_PARSE_PRECEDENCE_ADD_SUB
Definition parse_impl.h:32
@ REDUCT_PARSE_PRECEDENCE_COMPARISON
Definition parse_impl.h:29
@ REDUCT_PARSE_PRECEDENCE_MUL_DIV
Definition parse_impl.h:33
@ REDUCT_PARSE_PRECEDENCE_LOGICAL_OR
Definition parse_impl.h:27
@ REDUCT_PARSE_PRECEDENCE_LOGICAL_AND
Definition parse_impl.h:28
Atom structure.
Definition atom.h:48
Input structure.
Definition core.h:38
const char * end
Definition core.h:41
const char * buffer
Definition core.h:40
Item structure.
Definition item.h:57
reduct_uint32_t position
The position in the input buffer where the item was parsed.
Definition item.h:59
struct reduct_input * input
The parsed input that created this item.
Definition item.h:58
reduct_item_flags_t flags
Flags for the item.
Definition item.h:60
reduct_atom_t atom
An atom.
Definition item.h:66
reduct_item_type_t type
The type of the item.
Definition item.h:61
List structure.
Definition list.h:48
reduct_uint32_t length
Total number of elements.
Definition list.h:49
reduct_list_t * stack[REDUCT_PARSE_STACK_MAX]
Definition parse_impl.h:20
const char * ptr
Definition parse_impl.h:17
reduct_size_t current
Definition parse_impl.h:19
reduct_bool_t isInfix[REDUCT_PARSE_STACK_MAX]
Definition parse_impl.h:21
reduct_input_t * input
Definition parse_impl.h:18
State structure.
Definition core.h:61
reduct_error_t * error
Definition core.h:78