Reduct  v1.0.4-3-gdaf0d70
A functional and immutable language.
Loading...
Searching...
No Matches
eval_impl.h
Go to the documentation of this file.
1#ifndef REDUCT_EVAL_IMPL_H
2#define REDUCT_EVAL_IMPL_H 1
3
4#include "closure.h"
5#include "defs.h"
6#include "eval.h"
7#include "item.h"
8#include "standard.h"
9#include "parse.h"
10#include "compile.h"
11
13{
14 REDUCT_ASSERT(reduct != REDUCT_NULL);
15 REDUCT_ASSERT(state != REDUCT_NULL);
16
17 state->frameCount = 0;
20 if (state->frames == REDUCT_NULL)
21 {
22 REDUCT_ERROR_INTERNAL(reduct, "out of memory");
23 }
24
25 state->regCount = 1;
28 if (state->regs == REDUCT_NULL)
29 {
30 REDUCT_FREE(state->frames);
31 REDUCT_ERROR_INTERNAL(reduct, "out of memory");
32 }
33 state->regs[0] = reduct_handle_nil(reduct);
34}
35
43
45 reduct_uint32_t neededRegs)
46{
47 REDUCT_ASSERT(reduct != REDUCT_NULL);
48 REDUCT_ASSERT(state != REDUCT_NULL);
49
50 if (REDUCT_LIKELY(neededRegs <= state->regCapacity))
51 {
52 return;
53 }
54
55 while (neededRegs > state->regCapacity)
56 {
58 }
60 if (newRegs == REDUCT_NULL)
61 {
63 REDUCT_ERROR_INTERNAL(reduct, "out of memory");
64 }
65 state->regs = newRegs;
66}
67
69 reduct_closure_t* closure, reduct_uint32_t target)
70{
71 REDUCT_ASSERT(reduct != REDUCT_NULL);
72 REDUCT_ASSERT(state != REDUCT_NULL);
73 REDUCT_ASSERT(closure != REDUCT_NULL);
74
75 if (REDUCT_UNLIKELY(state->frameCount >= state->frameCapacity))
76 {
78 reduct_eval_frame_t* newFrames =
80 if (newFrames == REDUCT_NULL)
81 {
83 REDUCT_ERROR_INTERNAL(reduct, "out of memory");
84 }
85 state->frames = newFrames;
86 }
87
88 reduct_uint32_t neededRegs = target + closure->function->registerCount;
89 reduct_eval_ensure_regs(reduct, state, neededRegs);
90
91 reduct_eval_frame_t* frame = &state->frames[state->frameCount++];
92 frame->closure = closure;
93 frame->ip = closure->function->insts;
94 frame->base = target;
95 frame->prevRegCount = state->regCount;
96
97 state->regCount = neededRegs;
98}
99
101{
102 REDUCT_ASSERT(state != REDUCT_NULL);
103 REDUCT_ASSERT(state->frameCount > 0);
104
105 reduct_eval_frame_t* frame = &state->frames[--state->frameCount];
106 state->regCount = frame->prevRegCount;
107}
108
110 reduct_closure_t* closure)
111{
112 REDUCT_ASSERT(reduct != REDUCT_NULL);
113 REDUCT_ASSERT(state != REDUCT_NULL);
114 REDUCT_ASSERT(state->frameCount > 0);
115 REDUCT_ASSERT(closure != REDUCT_NULL);
116
117 reduct_eval_frame_t* frame = &state->frames[state->frameCount - 1];
118
119 reduct_uint32_t neededRegs = frame->base + closure->function->registerCount;
120 reduct_eval_ensure_regs(reduct, state, neededRegs);
121 state->regCount = neededRegs;
122
123 frame->closure = closure;
124 frame->ip = closure->function->insts;
125}
126
137
139{
140 REDUCT_ASSERT(reduct != REDUCT_NULL);
141 REDUCT_ASSERT(state != REDUCT_NULL);
142
143 reduct_eval_frame_t* frame = &state->frames[state->frameCount - 1];
144 reduct_inst_t* ip = frame->ip;
145 reduct_handle_t* base = state->regs + frame->base;
146 reduct_handle_t* constants = frame->closure->constants;
147 reduct_inst_t inst;
150
151 /// @todo Write some macro magic to turn this into a switch case if not using GCC or Clang
152#define DISPATCH() \
153 do \
154 { \
155 inst = *ip++; \
156 op = REDUCT_INST_GET_OP(inst); \
157 goto* dispatchTable[op]; \
158 } while (0)
159
160#define OP_COMPARE(_label, _op) \
161LABEL_C_OP(_label, { \
162 DECODE_A(); \
163 DECODE_B(); \
164 base[a] = REDUCT_HANDLE_COMPARE_FAST(reduct, &base[b], &valC, _op) ? REDUCT_HANDLE_TRUE() : REDUCT_HANDLE_FALSE(); \
165 DISPATCH(); \
166})
167
168#define OP_ARITH(_label, _op) \
169LABEL_C_OP(_label, { \
170 DECODE_A(); \
171 DECODE_B(); \
172 REDUCT_HANDLE_ARITHMETIC_FAST(reduct, &base[a], &base[b], &valC, _op); \
173 DISPATCH(); \
174})
175
176#define DECODE_A() reduct_uint32_t a = REDUCT_INST_GET_A(inst)
177#define DECODE_B() reduct_uint32_t b = REDUCT_INST_GET_B(inst)
178#define DECODE_C_REG() \
179 reduct_uint32_t c = REDUCT_INST_GET_C(inst); \
180 reduct_handle_t valC = base[c]
181#define DECODE_C_CONST() \
182 reduct_uint32_t c = REDUCT_INST_GET_C(inst); \
183 reduct_handle_t valC = constants[c]
184#define DECODE_SBX() reduct_int32_t sbx = REDUCT_INST_GET_SBX(inst)
185
186#define ERROR_CHECK(_expr, ...) \
187 do \
188 { \
189 if (REDUCT_UNLIKELY(!(_expr))) \
190 { \
191 frame->ip = ip; \
192 REDUCT_ERROR_RUNTIME(__VA_ARGS__); \
193 } \
194 } while (0)
195
196#define OP_ENTRY(_op, _label) [_op] = &&_label, [_op | REDUCT_MODE_CONST] = &&_label
197
198#define OP_ENTRY_C(_op, _label) [_op] = &&_label, [_op | REDUCT_MODE_CONST] = &&_label##_k
199
200#define OP_BITWISE(_label, _op) \
201LABEL_C_OP(_label, { \
202 DECODE_A(); \
203 DECODE_B(); \
204 base[a] = REDUCT_HANDLE_FROM_INT(reduct_get_int(reduct, &base[b]) _op reduct_get_int(reduct, &valC)); \
205 DISPATCH(); \
206})
207
208#define OP_EQUALITY(_label, _func, _truth) \
209LABEL_C_OP(_label, { \
210 DECODE_A(); \
211 DECODE_B(); \
212 base[a] = (_func(reduct, &base[b], &valC) == _truth) ? REDUCT_HANDLE_TRUE() : REDUCT_HANDLE_FALSE(); \
213 DISPATCH(); \
214})
215
216 void* dispatchTable[] = {
217 OP_ENTRY(REDUCT_OPCODE_NONE, label_none),
218 OP_ENTRY(REDUCT_OPCODE_LIST, label_list),
219 OP_ENTRY(REDUCT_OPCODE_JMP, label_jmp),
220 OP_ENTRY(REDUCT_OPCODE_JMPF, label_jmpf),
221 OP_ENTRY(REDUCT_OPCODE_JMPT, label_jmpt),
222 OP_ENTRY_C(REDUCT_OPCODE_CALL, label_call),
223 OP_ENTRY_C(REDUCT_OPCODE_MOV, label_mov),
224 OP_ENTRY_C(REDUCT_OPCODE_RET, label_ret),
225 OP_ENTRY_C(REDUCT_OPCODE_APPEND, label_append),
226 OP_ENTRY_C(REDUCT_OPCODE_EQ, label_eq),
227 OP_ENTRY_C(REDUCT_OPCODE_NEQ, label_neq),
228 OP_ENTRY_C(REDUCT_OPCODE_SEQ, label_seq),
229 OP_ENTRY_C(REDUCT_OPCODE_SNEQ, label_sneq),
230 OP_ENTRY_C(REDUCT_OPCODE_LT, label_lt),
231 OP_ENTRY_C(REDUCT_OPCODE_LE, label_le),
232 OP_ENTRY_C(REDUCT_OPCODE_GT, label_gt),
233 OP_ENTRY_C(REDUCT_OPCODE_GE, label_ge),
234 OP_ENTRY_C(REDUCT_OPCODE_ADD, label_add),
235 OP_ENTRY_C(REDUCT_OPCODE_SUB, label_sub),
236 OP_ENTRY_C(REDUCT_OPCODE_MUL, label_mul),
237 OP_ENTRY_C(REDUCT_OPCODE_DIV, label_div),
238 OP_ENTRY_C(REDUCT_OPCODE_MOD, label_mod),
239 OP_ENTRY_C(REDUCT_OPCODE_BAND, label_band),
240 OP_ENTRY_C(REDUCT_OPCODE_BOR, label_bor),
241 OP_ENTRY_C(REDUCT_OPCODE_BXOR, label_bxor),
242 OP_ENTRY_C(REDUCT_OPCODE_BNOT, label_bnot),
243 OP_ENTRY_C(REDUCT_OPCODE_SHL, label_shl),
244 OP_ENTRY_C(REDUCT_OPCODE_SHR, label_shr),
245 OP_ENTRY(REDUCT_OPCODE_CLOSURE, label_closure),
246 OP_ENTRY_C(REDUCT_OPCODE_CAPTURE, label_capture),
247 OP_ENTRY_C(REDUCT_OPCODE_TAILCALL, label_tailcall),
248 };
249
250#define LABEL_C_OP(_label, ...) \
251_label: \
252{ \
253 DECODE_C_REG(); \
254 __VA_ARGS__ \
255} \
256 _label##_k: \
257 { \
258 DECODE_C_CONST(); \
259 __VA_ARGS__ \
260 }
261
262 DISPATCH();
263label_none:
264 frame->ip = ip;
265 REDUCT_ERROR_RUNTIME(reduct, "invalid opcode, %u", inst);
266label_list:
267{
268 DECODE_A();
269 base[a] = REDUCT_HANDLE_FROM_LIST(reduct_list_new(reduct));
270 DISPATCH();
271}
272label_jmp:
273{
274 DECODE_SBX();
275 ip += sbx;
276 DISPATCH();
277}
278label_jmpf:
279{
280 DECODE_A();
281 DECODE_SBX();
282 reduct_handle_t val = base[a];
283 if (REDUCT_LIKELY(val == REDUCT_HANDLE_FALSE()) ||
285 {
286 ip += sbx;
287 }
288 DISPATCH();
289}
290label_jmpt:
291{
292 DECODE_A();
293 DECODE_SBX();
294 reduct_handle_t val = base[a];
295 if (REDUCT_LIKELY(val == REDUCT_HANDLE_TRUE()) ||
297 {
298 ip += sbx;
299 }
300 DISPATCH();
301}
302LABEL_C_OP(label_call, {
303 DECODE_A();
304 DECODE_B();
305 ERROR_CHECK(REDUCT_HANDLE_IS_ITEM(&valC), reduct, REDUCT_NULL, "attempt to call non-callable %s",
309 {
310 reduct_closure_t* closure = &item->closure;
311 ERROR_CHECK(b == closure->function->arity, reduct, REDUCT_NULL, "expected %d arguments, got %d",
312 closure->function->arity, b);
313
314 frame->ip = ip;
315 reduct_eval_push_frame(reduct, state, closure, frame->base + a);
316
317 frame = &state->frames[state->frameCount - 1];
318 ip = frame->ip;
319 base = state->regs + frame->base;
320 constants = frame->closure->constants;
321
322 DISPATCH();
323 }
325 {
326 reduct_handle_t* args = &base[a];
327 frame->ip = ip;
328 reduct_handle_t result = item->atom.native(reduct, b, args);
329
330 frame = &state->frames[state->frameCount - 1];
331 base = state->regs + frame->base;
332 base[a] = result;
333 constants = frame->closure->constants;
334
335 DISPATCH();
336 }
337
338 frame->ip = ip;
339 REDUCT_ERROR_RUNTIME(reduct, "attempt to call non-callable %s", reduct_item_type_str(item->type));
340})
341LABEL_C_OP(label_tailcall, {
342 DECODE_A();
343 DECODE_B();
344 ERROR_CHECK(REDUCT_HANDLE_IS_ITEM(&valC), reduct, REDUCT_NULL, "attempt to call non-callable %s",
348 {
349 reduct_closure_t* closure = &item->closure;
350 ERROR_CHECK(b == closure->function->arity, reduct, REDUCT_NULL, "expected %d arguments, got %d",
351 closure->function->arity, b);
352
353 if (a != 0)
354 {
355 for (reduct_uint32_t i = 0; i < b; i++)
356 {
357 base[i] = base[a + i];
358 }
359 }
360
361 reduct_eval_tail_frame(reduct, state, closure);
362
363 frame = &state->frames[state->frameCount - 1];
364 ip = frame->ip;
365 base = state->regs + frame->base;
366 constants = frame->closure->constants;
367
368 DISPATCH();
369 }
371 {
372 reduct_handle_t* args = &base[a];
373 frame->ip = ip;
374 reduct_handle_t res = item->atom.native(reduct, b, args);
375
376 frame = &state->frames[state->frameCount - 1];
377 state->regs[frame->base] = res;
379
380 if (REDUCT_UNLIKELY(state->frameCount == initialFrameCount))
381 {
382 result = res;
383 goto eval_end;
384 }
385
386 frame = &state->frames[state->frameCount - 1];
387 ip = frame->ip;
388 base = state->regs + frame->base;
389 constants = frame->closure->constants;
390
391 DISPATCH();
392 }
393
394 frame->ip = ip;
395 REDUCT_ERROR_RUNTIME(reduct, "attempt to call non-callable %s", reduct_item_type_str(item->type));
396})
397LABEL_C_OP(label_mov, {
398 DECODE_A();
399 base[a] = valC;
400 DISPATCH();
401})
402LABEL_C_OP(label_ret, {
403 state->regs[frame->base] = valC;
405 if (REDUCT_UNLIKELY(state->frameCount == initialFrameCount))
406 {
407 result = valC;
408 goto eval_end;
409 }
410 frame = &state->frames[state->frameCount - 1];
411 ip = frame->ip;
412 base = state->regs + frame->base;
413 constants = frame->closure->constants;
414 DISPATCH();
415})
416LABEL_C_OP(label_append, {
417 DECODE_A();
418 ERROR_CHECK(REDUCT_HANDLE_IS_ITEM(&base[a]), reduct, REDUCT_NULL, "APPEND expected a list");
419 reduct_item_t* item = REDUCT_HANDLE_TO_ITEM(&base[a]);
420 ERROR_CHECK(item->type == REDUCT_ITEM_TYPE_LIST, reduct, REDUCT_NULL, "APPEND expected a list");
421 reduct_list_t* listPtr = &item->list;
422 reduct_list_append(reduct, listPtr, valC);
423 DISPATCH();
424})
425OP_COMPARE(label_eq, ==)
426OP_COMPARE(label_neq, !=)
429OP_COMPARE(label_lt, <)
430OP_COMPARE(label_le, <=)
431OP_COMPARE(label_gt, >)
432OP_COMPARE(label_ge, >=)
433OP_ARITH(label_add, +)
434OP_ARITH(label_sub, -)
435OP_ARITH(label_mul, *)
436OP_ARITH(label_div, /)
437LABEL_C_OP(label_mod, {
438 DECODE_A();
439 DECODE_B();
441 reduct_handle_promote(reduct, &base[b], &valC, &prom);
442 ERROR_CHECK(prom.type == REDUCT_PROMOTION_TYPE_INT, reduct, REDUCT_NULL, "invalid item type");
443 ERROR_CHECK(prom.b.intVal != 0, reduct, REDUCT_NULL, "modulo by zero");
444 base[a] = REDUCT_HANDLE_FROM_INT(prom.a.intVal % prom.b.intVal);
445 DISPATCH();
446})
447OP_BITWISE(label_band, &)
448OP_BITWISE(label_bor, |)
449OP_BITWISE(label_bxor, ^)
450LABEL_C_OP(label_bnot, {
451 DECODE_A();
452 base[a] = REDUCT_HANDLE_FROM_INT(~reduct_get_int(reduct, &valC));
453 DISPATCH();
454})
455LABEL_C_OP(label_shl, {
456 DECODE_A();
457 DECODE_B();
458 reduct_int64_t left = reduct_get_int(reduct, &valC);
459 ERROR_CHECK(left >= 0 && left < 64, reduct, REDUCT_NULL, "expected left shift amount 0-63, got %ld", left);
460 base[a] = REDUCT_HANDLE_FROM_INT(reduct_get_int(reduct, &base[b]) << left);
461 DISPATCH();
462})
463LABEL_C_OP(label_shr, {
464 DECODE_A();
465 DECODE_B();
466 reduct_int64_t right = reduct_get_int(reduct, &valC);
467 ERROR_CHECK(right >= 0 && right < 64, reduct, REDUCT_NULL, "expected right shift amount 0-63, got %ld", right);
468 base[a] = REDUCT_HANDLE_FROM_INT(reduct_get_int(reduct, &base[b]) >> right);
469 DISPATCH();
470})
471label_closure:
472{
473 DECODE_A();
475 reduct_handle_t protoHandle = frame->closure->constants[c];
476 ERROR_CHECK(REDUCT_HANDLE_IS_ITEM(&protoHandle), reduct, REDUCT_NULL, "expected closure prototype to be an item");
477 reduct_item_t* protoItem = REDUCT_HANDLE_TO_ITEM(&protoHandle);
479 "expected closure prototype to be a function, got %s", reduct_item_type_str(protoItem->type));
480
481 reduct_function_t* proto = &protoItem->function;
482 base[a] = REDUCT_HANDLE_FROM_CLOSURE(reduct_closure_new(reduct, proto));
483 DISPATCH();
484}
485LABEL_C_OP(label_capture, {
486 DECODE_A();
487 DECODE_B();
488 reduct_handle_t closureHandle = base[a];
489 reduct_closure_t* closurePtr = &REDUCT_HANDLE_TO_ITEM(&closureHandle)->closure;
490 closurePtr->constants[b] = valC;
491 DISPATCH();
492})
493eval_end:
494 // clang-format on
495 return result;
496}
497
499{
500 REDUCT_ASSERT(reduct != REDUCT_NULL);
501 REDUCT_ASSERT(function != REDUCT_NULL);
502
503 if (reduct->evalState == REDUCT_NULL)
504 {
505 reduct->evalState = (reduct_eval_state_t*)REDUCT_MALLOC(sizeof(reduct_eval_state_t));
506 reduct_eval_state_init(reduct, reduct->evalState);
507 }
508
509 reduct_closure_t* closure = reduct_closure_new(reduct, function);
510 reduct_eval_state_t* state = reduct->evalState;
511 reduct_uint32_t initialFrameCount = state->frameCount;
512
513 reduct_eval_push_frame(reduct, state, closure, state->regCount);
514
515 return reduct_eval_run(reduct, state, initialFrameCount);
516}
517
519{
520 REDUCT_ASSERT(reduct != REDUCT_NULL);
521 REDUCT_ASSERT(path != REDUCT_NULL);
522
523 reduct_handle_t parsed = reduct_parse_file(reduct, path);
524 reduct_function_t* function = reduct_compile(reduct, &parsed);
525 return reduct_eval(reduct, function);
526}
527
529{
530 REDUCT_ASSERT(reduct != REDUCT_NULL);
532
533 reduct_handle_t parsed = reduct_parse(reduct, str, len, "eval");
534 reduct_function_t* function = reduct_compile(reduct, &parsed);
535 return reduct_eval(reduct, function);
536}
537
539{
540 REDUCT_ASSERT(reduct != REDUCT_NULL);
541 REDUCT_ASSERT(argv != REDUCT_NULL || argc == 0);
542
543 if (!REDUCT_HANDLE_IS_ITEM(&callable))
544 {
545 REDUCT_ERROR_RUNTIME(reduct, "attempt to call non-callable value");
546 }
547
548 reduct_item_t* item = REDUCT_HANDLE_TO_ITEM(&callable);
549 if (item->flags & REDUCT_ITEM_FLAG_NATIVE)
550 {
551 return item->atom.native(reduct, argc, argv);
552 }
553
554 if (item->type == REDUCT_ITEM_TYPE_CLOSURE)
555 {
556 reduct_closure_t* closure = &item->closure;
557 if (argc != closure->function->arity)
558 {
559 REDUCT_ERROR_RUNTIME(reduct, "expected %ld arguments, got %ld", closure->function->arity, argc);
560 }
561
562 if (reduct->evalState == REDUCT_NULL)
563 {
565 if (reduct->evalState == REDUCT_NULL)
566 {
567 REDUCT_ERROR_INTERNAL(reduct, "out of memory");
568 }
569 reduct_eval_state_init(reduct, reduct->evalState);
570 }
571
572 reduct_eval_state_t* state = reduct->evalState;
573 reduct_uint32_t target = state->regCount;
574
575 if (REDUCT_UNLIKELY(target + argc > state->regCapacity))
576 {
577 reduct_bool_t argvInRegs = (argv >= state->regs && argv < state->regs + state->regCapacity);
578 reduct_uint32_t argvOffset = argvInRegs ? (reduct_uint32_t)(argv - state->regs) : 0;
579
580 reduct_eval_ensure_regs(reduct, state, target + argc);
581
582 if (argvInRegs)
583 {
584 argv = state->regs + argvOffset;
585 }
586 }
587
588 for (reduct_size_t i = 0; i < argc; i++)
589 {
590 state->regs[target + i] = argv[i];
591 }
592
593 reduct_uint32_t initialFrameCount = state->frameCount;
594 reduct_eval_push_frame(reduct, state, closure, target);
595
596 return reduct_eval_run(reduct, state, initialFrameCount);
597 }
598
599 REDUCT_ERROR_RUNTIME(reduct, "attempt to call non-callable value");
600}
601
602#endif
Closure management.
Bytecode compilation.
#define REDUCT_MALLOC(_size)
Definition defs.h:27
#define REDUCT_LIKELY(_x)
Definition defs.h:117
size_t reduct_size_t
Definition defs.h:100
#define REDUCT_UNLIKELY(_x)
Definition defs.h:118
reduct_bool_t
Boolean type.
Definition defs.h:135
@ REDUCT_FALSE
Definition defs.h:137
@ REDUCT_TRUE
Definition defs.h:136
int64_t reduct_int64_t
Definition defs.h:92
#define REDUCT_REALLOC(_ptr, _size)
Definition defs.h:29
reduct_uint64_t reduct_handle_t
Handle type.
Definition defs.h:189
uint32_t reduct_uint32_t
Definition defs.h:95
#define REDUCT_ALWAYS_INLINE
Definition defs.h:120
#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
Virtual machine evaluation.
static REDUCT_ALWAYS_INLINE void reduct_eval_push_frame(reduct_t *reduct, reduct_eval_state_t *state, reduct_closure_t *closure, reduct_uint32_t target)
Definition eval_impl.h:68
static REDUCT_ALWAYS_INLINE void reduct_eval_ensure_regs(reduct_t *reduct, reduct_eval_state_t *state, reduct_uint32_t neededRegs)
Definition eval_impl.h:44
static REDUCT_ALWAYS_INLINE void reduct_eval_tail_frame(reduct_t *reduct, reduct_eval_state_t *state, reduct_closure_t *closure)
Definition eval_impl.h:109
static reduct_handle_t reduct_eval_run(reduct_t *reduct, reduct_eval_state_t *state, reduct_uint32_t initialFrameCount)
Definition eval_impl.h:138
#define OP_ARITH(_label, _op)
#define OP_ENTRY_C(_op, _label)
static REDUCT_ALWAYS_INLINE void reduct_eval_pop_frame(reduct_eval_state_t *state)
Definition eval_impl.h:100
#define LABEL_C_OP(_label,...)
#define ERROR_CHECK(_expr,...)
REDUCT_API reduct_handle_t reduct_eval(struct reduct *reduct, reduct_function_t *function)
Definition eval_impl.h:498
#define OP_BITWISE(_label, _op)
#define DISPATCH()
#define DECODE_SBX()
#define OP_ENTRY(_op, _label)
#define OP_COMPARE(_label, _op)
#define OP_EQUALITY(_label, _func, _truth)
#define DECODE_A()
static void reduct_eval_state_init(reduct_t *reduct, reduct_eval_state_t *state)
Definition eval_impl.h:12
#define DECODE_B()
REDUCT_API reduct_closure_t * reduct_closure_new(struct reduct *reduct, reduct_function_t *function)
Allocate a new closure.
REDUCT_API reduct_function_t * reduct_compile(reduct_t *reduct, reduct_handle_t *ast)
Compiles a Reduct AST into a callable bytecode function.
#define REDUCT_ERROR_RUNTIME(_reduct,...)
Throw a runtime error using the jump buffer in the error structure.
Definition error.h:175
#define REDUCT_ERROR_INTERNAL(_reduct,...)
Throw an internal error using the jump buffer in the error structure.
Definition error.h:183
REDUCT_API reduct_handle_t reduct_eval_string(reduct_t *reduct, const char *str, reduct_size_t len)
Parses, compiles and evaluates a string.
Definition eval_impl.h:528
REDUCT_API void reduct_eval_state_deinit(reduct_eval_state_t *state)
Deinitialize an evaluation state structure.
Definition eval_impl.h:36
#define REDUCT_EVAL_REGS_INITIAL
The initial amount of registers.
Definition eval.h:18
#define REDUCT_EVAL_FRAMES_INITIAL
The initial size of the frames array.
Definition eval.h:21
REDUCT_API reduct_handle_t reduct_eval_file(reduct_t *reduct, const char *path)
Parses, compiles and evaluates a file.
Definition eval_impl.h:518
#define REDUCT_EVAL_REGS_GROWTH_FACTOR
The growth factor of the registers array.
Definition eval.h:19
REDUCT_API reduct_handle_t reduct_eval_call(reduct_t *reduct, reduct_handle_t callable, reduct_size_t argc, reduct_handle_t *argv)
Calls a Reduct callable (closure or native) with arguments.
Definition eval_impl.h:538
#define REDUCT_EVAL_FRAMES_GROWTH_FACTOR
The growth factor of the frames array.
Definition eval.h:22
#define REDUCT_HANDLE_FALSE()
Constant false handle.
Definition handle.h:267
#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
#define REDUCT_HANDLE_FROM_CLOSURE(_closure)
Create a handle from a closure pointer.
Definition handle.h:109
REDUCT_API void reduct_handle_promote(struct reduct *reduct, reduct_handle_t *a, reduct_handle_t *b, reduct_promotion_t *out)
Promote two handles to a common numeric type.
Definition handle_impl.h:54
REDUCT_API reduct_handle_t reduct_handle_nil(struct reduct *reduct)
Get the constant nil handle.
#define REDUCT_HANDLE_GET_TYPE(_handle)
Get the type of the item referenced by the handle, or REDUCT_ITEM_TYPE_ATOM if not an item.
Definition handle.h:153
REDUCT_API reduct_bool_t reduct_handle_is_equal(struct reduct *reduct, reduct_handle_t *a, reduct_handle_t *b)
Check if two items are exactly equal string-wise or structurally.
#define REDUCT_HANDLE_FROM_INT(_val)
Create a handle from an integer.
Definition handle.h:54
#define REDUCT_HANDLE_NONE
Invalid handle constant.
Definition handle.h:36
#define REDUCT_HANDLE_IS_TRUTHY(_handle)
Check if a handle is truthy.
Definition handle.h:338
#define REDUCT_HANDLE_TRUE()
Constant true handle.
Definition handle.h:269
@ REDUCT_PROMOTION_TYPE_INT
Definition handle.h:374
#define REDUCT_INST_GET_C(_inst)
Get the C operand from an instruction.
Definition inst.h:185
reduct_opcode_t
Opcode enumeration.
Definition inst.h:49
reduct_uint32_t reduct_inst_t
Instruction type.
Definition inst.h:97
@ REDUCT_OPCODE_DIV
(A, B, C) R(A) = R(B) / R/K(C)
Definition inst.h:71
@ REDUCT_OPCODE_JMPF
(A, sBx) Jump by sBx if R(A) is falsy.
Definition inst.h:53
@ REDUCT_OPCODE_JMPT
(A, sBx) Jump by sBx if R(A) is truthy.
Definition inst.h:54
@ REDUCT_OPCODE_APPEND
(A, C) Append value in R/K(C) to the back of the list in R(A).
Definition inst.h:59
@ REDUCT_OPCODE_SHR
(A, B, C) R(A) = R(B) >> R/K(C)
Definition inst.h:78
@ REDUCT_OPCODE_SEQ
(A, B, C) If R(B) === R/K(C) store true in R(A), else false.
Definition inst.h:62
@ REDUCT_OPCODE_SHL
(A, B, C) R(A) = R(B) << R/K(C)
Definition inst.h:77
@ REDUCT_OPCODE_SUB
(A, B, C) R(A) = R(B) - R/K(C)
Definition inst.h:69
@ REDUCT_OPCODE_NEQ
(A, B, C) If R(B) != R/K(C) store true in R(A), else false.
Definition inst.h:61
@ REDUCT_OPCODE_MOV
(A, C) Move value in R/K(C) to R(A).
Definition inst.h:57
@ REDUCT_OPCODE_MUL
(A, B, C) R(A) = R(B) * R/K(C)
Definition inst.h:70
@ REDUCT_OPCODE_ADD
(A, B, C) R(A) = R(B) + R/K(C)
Definition inst.h:68
@ REDUCT_OPCODE_BAND
(A, B, C) R(A) = R(B) & R/K(C)
Definition inst.h:73
@ REDUCT_OPCODE_RET
(C) Return value in R/K(C).
Definition inst.h:58
@ REDUCT_OPCODE_BNOT
(A, C) R(A) = ~R/K(C)
Definition inst.h:76
@ REDUCT_OPCODE_EQ
(A, B, C) If R(B) == R/K(C) store true in R(A), else false.
Definition inst.h:60
@ REDUCT_OPCODE_CALL
(A, B, C) Call callable in R/K(C) with B args starting from R(A). Result in R(A).
Definition inst.h:56
@ REDUCT_OPCODE_GT
(A, B, C) If R(B) > R/K(C) store true in R(A), else false.
Definition inst.h:66
@ REDUCT_OPCODE_JMP
(sBx) Unconditional jump by relative offset sBx.
Definition inst.h:52
@ REDUCT_OPCODE_NONE
Definition inst.h:50
@ REDUCT_OPCODE_SNEQ
(A, B, C) If R(B) !== R/K(C) store true in R(A), else false.
Definition inst.h:63
@ REDUCT_OPCODE_GE
(A, B, C) If R(B) >= R/K(C) store true in R(A), else false.
Definition inst.h:67
@ REDUCT_OPCODE_BOR
(A, B, C) R(A) = R(B) | R/K(C)
Definition inst.h:74
@ REDUCT_OPCODE_CLOSURE
(A, C) Wrap the function prototype in K(C) in a closure and store in R(A).
Definition inst.h:79
@ REDUCT_OPCODE_LE
(A, B, C) If R(B) <= R/K(C) store true in R(A), else false.
Definition inst.h:65
@ REDUCT_OPCODE_LIST
(A) Create a new list and store it in R(A).
Definition inst.h:51
@ REDUCT_OPCODE_TAILCALL
(A, B, C) Tail call callable in R/K(C) with B args starting from R(A).
Definition inst.h:81
@ REDUCT_OPCODE_BXOR
(A, B, C) R(A) = R(B) ^ R/K(C)
Definition inst.h:75
@ REDUCT_OPCODE_CAPTURE
(A, B, C) Capture R/K(C) into constant slot B in closure R(A).
Definition inst.h:80
@ REDUCT_OPCODE_MOD
(A, B, C) R(A) = R(B) % R/K(C)
Definition inst.h:72
@ REDUCT_OPCODE_LT
(A, B, C) If R(B) < R/K(C) store true in R(A), else false.
Definition inst.h:64
#define REDUCT_ITEM_TYPE_LIST
A list.
Definition item.h:28
REDUCT_API const char * reduct_item_type_str(reduct_item_type_t type)
Get the string representation of an Reduct item type.
Definition item_impl.h:139
#define REDUCT_ITEM_TYPE_FUNCTION
A function.
Definition item.h:29
#define REDUCT_ITEM_TYPE_CLOSURE
A closure.
Definition item.h:30
#define REDUCT_ITEM_FLAG_NATIVE
Item is an atom and a native function.
Definition item.h:42
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
REDUCT_API reduct_handle_t reduct_get_int(struct reduct *reduct, reduct_handle_t *handle)
Item management.
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.
Built-in library registration and operations.
reduct_eval_frame_t * frame
Definition eval_impl.h:129
reduct_inst_t * ip
Definition eval_impl.h:130
reduct_inst_t inst
Definition eval_impl.h:133
reduct_handle_t result
Definition eval_impl.h:135
reduct_handle_t * base
Definition eval_impl.h:131
reduct_opcode_t op
Definition eval_impl.h:134
reduct_handle_t * constants
Definition eval_impl.h:132
reduct_native_fn native
Native function, item must have REDUCT_ITEM_FLAG_NATIVE.
Definition atom.h:57
Closure structure.
Definition closure.h:26
reduct_handle_t * constants
The array of constant slots forming the constant template.
Definition closure.h:28
reduct_function_t * function
Pointer to the prototype function item.
Definition closure.h:27
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
reduct_uint32_t prevRegCount
The previous register count to restore upon return.
Definition eval.h:33
reduct_uint32_t base
The base register, where the functions registers start.
Definition eval.h:32
Evaluation state structure.
Definition eval.h:41
reduct_uint32_t regCount
Definition eval.h:46
reduct_handle_t * regs
Definition eval.h:45
reduct_uint32_t frameCapacity
Definition eval.h:44
reduct_eval_frame_t * frames
Definition eval.h:42
reduct_uint32_t frameCount
Definition eval.h:43
reduct_uint32_t regCapacity
Definition eval.h:47
Compiled function structure.
Definition function.h:78
reduct_inst_t * insts
An array of instructions.
Definition function.h:81
reduct_uint16_t registerCount
The number of registers the function uses.
Definition function.h:86
reduct_uint8_t arity
The number of arguments the function expects.
Definition function.h:87
Item structure.
Definition item.h:57
reduct_list_t list
A list.
Definition item.h:67
reduct_closure_t closure
A closure.
Definition item.h:70
reduct_function_t function
A function.
Definition item.h:69
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
Promotion result for numeric operations.
Definition handle.h:383
reduct_int64_t intVal
Definition handle.h:386
union reduct_promotion_t::@7 a
union reduct_promotion_t::@8 b
reduct_promotion_type_t type
Definition handle.h:384
State structure.
Definition core.h:61
struct reduct_eval_state * evalState
Definition core.h:79