Reduct  v1.0.4-3-gdaf0d70
A functional and immutable language.
Loading...
Searching...
No Matches
intrinsic_impl.h
Go to the documentation of this file.
1#ifndef REDUCT_INTRINSIC_IMPL_H
2#define REDUCT_INTRINSIC_IMPL_H 1
3
4#include "compile.h"
5#include "intrinsic.h"
6#include "item.h"
7#include "stdlib.h"
8
10 reduct_size_t expected, const char* name)
11{
12 if (REDUCT_UNLIKELY(list->length != (reduct_uint32_t)expected + 1))
13 {
14 REDUCT_ERROR_COMPILE(compiler, list, "%s expects exactly %zu argument(s), got %zu", name,
15 (reduct_size_t)expected, (reduct_size_t)list->length - 1);
16 }
17}
18
20 const char* name)
21{
22 if (REDUCT_UNLIKELY(list->length < (reduct_uint32_t)min + 1))
23 {
24 REDUCT_ERROR_COMPILE(compiler, list, "%s expects at least %zu argument(s), got %zu", name, (reduct_size_t)min,
25 (reduct_size_t)list->length - 1);
26 }
27}
28
30 reduct_size_t min, reduct_size_t max, const char* name)
31{
32 if (REDUCT_UNLIKELY(list->length < (reduct_uint32_t)min + 1 || list->length > (reduct_uint32_t)max + 1))
33 {
34 REDUCT_ERROR_COMPILE(compiler, list, "%s expects between %zu and %zu argument(s), got %zu", name,
35 (reduct_size_t)min, (reduct_size_t)max, (reduct_size_t)list->length - 1);
36 }
37}
38
40{
41 REDUCT_ASSERT(compiler != REDUCT_NULL);
44
45 reduct_intrinsic_check_arity(compiler, list, 1, "quote");
46 *out = REDUCT_EXPR_CONST_ITEM(compiler, reduct_list_nth_item(compiler->reduct, &list->list, 1));
47}
48
50{
51 REDUCT_ASSERT(compiler != REDUCT_NULL);
54
55 reduct_reg_t target = reduct_expr_get_reg(compiler, out);
56 reduct_compile_list(compiler, target);
57
59 REDUCT_LIST_FOR_EACH_AT(&h, &list->list, 1)
60 {
62 reduct_expr_build(compiler, REDUCT_HANDLE_TO_ITEM(&h), &argExpr);
63
64 reduct_compile_append(compiler, target, &argExpr);
65
66 reduct_expr_done(compiler, &argExpr);
67 }
68
69 *out = REDUCT_EXPR_REG(target);
70}
71
73 reduct_reg_t target)
74{
75 reduct_expr_t expr = REDUCT_EXPR_TARGET(target);
76 reduct_expr_build(compiler, item, &expr);
77 if (expr.mode == REDUCT_MODE_NONE)
78 {
79 reduct_expr_t nil = REDUCT_EXPR_NIL(compiler);
80 reduct_compile_move(compiler, target, &nil);
81 }
82 else if (expr.mode != REDUCT_MODE_REG || expr.reg != target)
83 {
84 reduct_compile_move(compiler, target, &expr);
85 reduct_expr_done(compiler, &expr);
86 }
87}
88
90 reduct_expr_t* out)
91{
92 REDUCT_ASSERT(compiler != REDUCT_NULL);
95
96 if (startIdx >= list->length)
97 {
98 *out = REDUCT_EXPR_NONE();
99 return;
100 }
101
102 reduct_uint16_t savedLocalCount = compiler->localCount;
103
104 reduct_reg_t targetHint = REDUCT_EXPR_GET_TARGET(out);
106 REDUCT_LIST_FOR_EACH_AT(&h, &list->list, startIdx)
107 {
109
110 if (_iter.index == list->length)
111 {
112 if (targetHint != REDUCT_REG_INVALID)
113 {
114 reduct_compile_build_into_target(compiler, item, targetHint);
115 *out = REDUCT_EXPR_REG(targetHint);
116 }
117 else
118 {
119 reduct_expr_build(compiler, item, out);
120 }
121 }
122 else
123 {
125 reduct_expr_build(compiler, item, &expr);
126 reduct_expr_done(compiler, &expr);
127 }
128 }
129
130 reduct_local_pop(compiler, savedLocalCount, out);
131}
132
134{
135 reduct_intrinsic_block_generic(compiler, list, 1, out);
136}
137
139{
140 REDUCT_ASSERT(compiler != REDUCT_NULL);
141 REDUCT_ASSERT(list != REDUCT_NULL);
143
144 reduct_intrinsic_check_min_arity(compiler, list, 2, "lambda");
145
146 reduct_item_t* args = reduct_list_nth_item(compiler->reduct, &list->list, 1);
147 if (args->type != REDUCT_ITEM_TYPE_LIST)
148 {
149 REDUCT_ERROR_COMPILE(compiler, args, "lambda expects a list of arguments, got %s",
151 }
152
153 if (args->length > 255)
154 {
155 REDUCT_ERROR_COMPILE(compiler, args, "lambda expects at most 255 arguments, got %d", args->length);
156 }
157
159 reduct_item_t* funcItem = REDUCT_CONTAINER_OF(func, reduct_item_t, function);
160 funcItem->input = list->input;
162 reduct_const_t funcConst = reduct_function_lookup_constant(compiler->reduct, compiler->function, &slot);
163
164 func->arity = (reduct_uint8_t)args->length;
165
166 reduct_compiler_t childCompiler;
167 reduct_compiler_init(&childCompiler, compiler->reduct, func, compiler);
168
170 REDUCT_LIST_FOR_EACH(&h, &args->list)
171 {
173 if (argName->type != REDUCT_ITEM_TYPE_ATOM)
174 {
175 REDUCT_ERROR_COMPILE(compiler, argName, "lambda expects a list of atoms as arguments, got %s",
176 reduct_item_type_str(argName->type));
177 }
178 reduct_local_add_arg(&childCompiler, &argName->atom);
179 }
180
181 reduct_expr_t bodyExpr = REDUCT_EXPR_NONE();
182 reduct_intrinsic_block_generic(&childCompiler, list, 2, &bodyExpr);
183 reduct_compile_return(&childCompiler, &bodyExpr);
184 reduct_expr_done(&childCompiler, &bodyExpr);
185
186 reduct_compiler_deinit(&childCompiler);
187
188 reduct_reg_t target = reduct_expr_get_reg(compiler, out);
189 reduct_compile_closure(compiler, target, funcConst);
190
191 for (reduct_uint32_t i = 0; i < func->constantCount; i++)
192 {
193 if (func->constants[i].type == REDUCT_CONST_SLOT_ITEM)
194 {
195 continue;
196 }
197 reduct_atom_t* captureName = func->constants[i].capture;
198 reduct_local_t* captured = reduct_local_lookup(compiler, func->constants[i].capture);
199 if (captured == REDUCT_NULL)
200 {
201 REDUCT_ERROR_COMPILE(compiler, REDUCT_CONTAINER_OF(captureName, reduct_item_t, atom),
202 "undefined variable '%s'", captureName->string);
203 }
204
205 if (!REDUCT_LOCAL_IS_DEFINED(captured))
206 {
207 reduct_expr_t selfExpr = REDUCT_EXPR_REG(target);
208 reduct_compile_capture(compiler, target, i, &selfExpr);
209 continue;
210 }
211
212 reduct_compile_capture(compiler, target, i, &captured->expr);
213 }
214
215 *out = REDUCT_EXPR_REG(target);
216}
217
219{
220 REDUCT_ASSERT(compiler != REDUCT_NULL);
221 REDUCT_ASSERT(list != REDUCT_NULL);
223
224 reduct_intrinsic_check_min_arity(compiler, list, 1, "->");
225
227 reduct_expr_build(compiler, reduct_list_nth_item(compiler->reduct, &list->list, 1), &current);
228
230 REDUCT_LIST_FOR_EACH_AT(&h, &list->list, 2)
231 {
233 reduct_item_t* head;
234 reduct_uint32_t arity;
235
236 if (step->type == REDUCT_ITEM_TYPE_LIST)
237 {
238 if (step->length == 0)
239 {
240 continue;
241 }
242 head = reduct_list_nth_item(compiler->reduct, &step->list, 0);
243 arity = step->length;
244 }
245 else
246 {
247 head = step;
248 arity = 1;
249 }
250
251 reduct_reg_t base = reduct_reg_alloc_range(compiler, arity);
252
253 reduct_compile_move(compiler, base, &current);
254 reduct_expr_done(compiler, &current);
255
256 if (step->type == REDUCT_ITEM_TYPE_LIST)
257 {
258 reduct_handle_t argH;
259 REDUCT_LIST_FOR_EACH_AT(&argH, &step->list, 1)
260 {
261 reduct_reg_t argReg = (reduct_reg_t)(base + _iter.index - 1);
262 reduct_expr_t argExpr = REDUCT_EXPR_TARGET(argReg);
263 reduct_expr_build(compiler, REDUCT_HANDLE_TO_ITEM(&argH), &argExpr);
264
265 if (argExpr.mode != REDUCT_MODE_REG || argExpr.reg != argReg)
266 {
267 reduct_compile_move(compiler, argReg, &argExpr);
268 reduct_expr_done(compiler, &argExpr);
269 }
270 }
271 }
272
273 reduct_expr_t callable = REDUCT_EXPR_NONE();
274 reduct_expr_build(compiler, head, &callable);
275 reduct_compile_call(compiler, base, &callable, arity);
276 reduct_expr_done(compiler, &callable);
277
278 if (arity > 1)
279 {
280 reduct_reg_free_range(compiler, (reduct_reg_t)(base + 1), arity - 1);
281 }
282
283 current = REDUCT_EXPR_REG(base);
284 }
285
286 *out = current;
287}
288
290{
291 REDUCT_ASSERT(compiler != REDUCT_NULL);
292 REDUCT_ASSERT(list != REDUCT_NULL);
294
295 reduct_intrinsic_check_arity(compiler, list, 2, "def");
296
297 reduct_item_t* name = reduct_list_nth_item(compiler->reduct, &list->list, 1);
298 if (name->type != REDUCT_ITEM_TYPE_ATOM)
299 {
300 REDUCT_ERROR_COMPILE(compiler, name, "def expects an atom as the name, got %s",
302 }
303
304 reduct_local_t* local = reduct_local_def(compiler, &name->atom);
305
307 reduct_expr_build(compiler, reduct_list_nth_item(compiler->reduct, &list->list, 2), &valExpr);
308
309 reduct_local_def_done(compiler, local, &valExpr);
310 reduct_expr_done(compiler, &valExpr);
311
312 *out = valExpr;
313}
314
316 reduct_handle_t* outItem)
317{
318 REDUCT_ASSERT(compiler != REDUCT_NULL);
319 REDUCT_ASSERT(expr != REDUCT_NULL);
320 REDUCT_ASSERT(outItem != REDUCT_NULL);
321
322 if (expr->mode == REDUCT_MODE_CONST)
323 {
324 if (compiler->function->constants[expr->constant].type != REDUCT_CONST_SLOT_ITEM)
325 {
326 return REDUCT_FALSE;
327 }
328
329 *outItem = REDUCT_HANDLE_FROM_ITEM(compiler->function->constants[expr->constant].item);
330 return REDUCT_TRUE;
331 }
332 return REDUCT_FALSE;
333}
334
336 reduct_bool_t* isTruthy)
337{
338 REDUCT_ASSERT(compiler != REDUCT_NULL);
339 REDUCT_ASSERT(expr != REDUCT_NULL);
340 REDUCT_ASSERT(isTruthy != REDUCT_NULL);
341
342 reduct_handle_t item;
343 if (reduct_expr_get_item(compiler, expr, &item))
344 {
345 *isTruthy = REDUCT_HANDLE_IS_TRUTHY(&item);
346 return REDUCT_TRUE;
347 }
348 return REDUCT_FALSE;
349}
350
352{
354 if (pair->type != REDUCT_ITEM_TYPE_LIST || pair->length != 2)
355 {
356 REDUCT_ERROR_COMPILE(compiler, pair, "%s clauses must be lists of exactly two items, got %s (length %u)", name,
357 reduct_item_type_str(pair->type), pair->length);
358 }
359 return pair;
360}
361
363 reduct_handle_t right, reduct_bool_t* result)
364{
365 REDUCT_ASSERT(reduct != REDUCT_NULL);
366 REDUCT_ASSERT(result != REDUCT_NULL);
367
368 reduct_int64_t cmp = reduct_handle_compare(reduct, &left, &right);
369 switch (opBase)
370 {
371 case REDUCT_OPCODE_EQ:
372 *result = (cmp == 0);
373 return REDUCT_TRUE;
375 *result = (cmp != 0);
376 return REDUCT_TRUE;
378 *result = reduct_handle_is_equal(reduct, &left, &right);
379 return REDUCT_TRUE;
381 *result = !reduct_handle_is_equal(reduct, &left, &right);
382 return REDUCT_TRUE;
383 case REDUCT_OPCODE_LT:
384 *result = (cmp < 0);
385 return REDUCT_TRUE;
386 case REDUCT_OPCODE_LE:
387 *result = (cmp <= 0);
388 return REDUCT_TRUE;
389 case REDUCT_OPCODE_GT:
390 *result = (cmp > 0);
391 return REDUCT_TRUE;
392 case REDUCT_OPCODE_GE:
393 *result = (cmp >= 0);
394 return REDUCT_TRUE;
395 default:
396 return REDUCT_FALSE;
397 }
398}
399
401{
402 REDUCT_ASSERT(compiler != REDUCT_NULL);
403 REDUCT_ASSERT(list != REDUCT_NULL);
405
406 reduct_intrinsic_check_arity_range(compiler, list, 2, 3, "if");
407
408 reduct_expr_t condExpr = REDUCT_EXPR_NONE();
409 reduct_expr_build(compiler, reduct_list_nth_item(compiler->reduct, &list->list, 1), &condExpr);
410
411 reduct_bool_t isTruthy;
412 if (reduct_expr_is_known_truthy(compiler, &condExpr, &isTruthy))
413 {
414 reduct_expr_done(compiler, &condExpr);
415 if (isTruthy)
416 {
417 reduct_expr_build(compiler, reduct_list_nth_item(compiler->reduct, &list->list, 2), out);
418 }
419 else if (list->length == 4)
420 {
421 reduct_expr_build(compiler, reduct_list_nth_item(compiler->reduct, &list->list, 3), out);
422 }
423 else
424 {
425 *out = REDUCT_EXPR_NIL(compiler);
426 }
427 return;
428 }
429
430 reduct_reg_t target = reduct_expr_get_reg(compiler, out);
431
432 reduct_reg_t condReg = reduct_compile_move_or_alloc(compiler, &condExpr);
433 reduct_size_t jumpElse = reduct_compile_jump(compiler, REDUCT_OPCODE_JMPF, condReg);
434 reduct_expr_done(compiler, &condExpr);
435
436 reduct_compile_build_into_target(compiler, reduct_list_nth_item(compiler->reduct, &list->list, 2), target);
437
438 reduct_size_t jumpEnd = 0;
439 if (list->length == 4)
440 {
441 jumpEnd = reduct_compile_jump(compiler, REDUCT_OPCODE_JMP, 0);
442 }
443
444 reduct_compile_jump_patch(compiler, jumpElse);
445
446 if (list->length == 4)
447 {
448 reduct_compile_build_into_target(compiler, reduct_list_nth_item(compiler->reduct, &list->list, 3), target);
449 reduct_compile_jump_patch(compiler, jumpEnd);
450 }
451 else
452 {
453 reduct_expr_t nilExpr = REDUCT_EXPR_NIL(compiler);
454 reduct_compile_move(compiler, target, &nilExpr);
455 }
456
457 *out = REDUCT_EXPR_REG(target);
458}
459
461{
462 REDUCT_ASSERT(compiler != REDUCT_NULL);
463 REDUCT_ASSERT(list != REDUCT_NULL);
465
466 if (list->length < 2)
467 {
468 *out = REDUCT_EXPR_NIL(compiler);
469 return;
470 }
471
472 reduct_reg_t targetHint = REDUCT_EXPR_GET_TARGET(out);
475 reduct_size_t jumpCount = 0;
476 reduct_bool_t alwaysHit = REDUCT_FALSE;
477
479 REDUCT_LIST_FOR_EACH_AT(&h, &list->list, 1)
480 {
481 reduct_item_t* pair = reduct_intrinsic_get_pair(compiler, &h, "cond");
482
483 reduct_expr_t condExpr = REDUCT_EXPR_NONE();
484 reduct_expr_build(compiler, reduct_list_nth_item(compiler->reduct, &pair->list, 0), &condExpr);
485
486 reduct_bool_t isTruthy;
487 if (reduct_expr_is_known_truthy(compiler, &condExpr, &isTruthy))
488 {
489 reduct_expr_done(compiler, &condExpr);
490 if (!isTruthy)
491 {
492 continue;
493 }
494
495 if (target == REDUCT_REG_INVALID)
496 {
497 if (targetHint != REDUCT_REG_INVALID)
498 {
499 *out = REDUCT_EXPR_TARGET(targetHint);
500 }
501 else
502 {
503 *out = REDUCT_EXPR_NONE();
504 }
505 reduct_expr_build(compiler, reduct_list_nth_item(compiler->reduct, &pair->list, 1), out);
506 return;
507 }
508
509 reduct_compile_build_into_target(compiler, reduct_list_nth_item(compiler->reduct, &pair->list, 1), target);
510 alwaysHit = REDUCT_TRUE;
511 break;
512 }
513
514 if (target == REDUCT_REG_INVALID)
515 {
516 target = (targetHint != REDUCT_REG_INVALID) ? targetHint : reduct_reg_alloc(compiler);
517 }
518
519 reduct_reg_t condReg = reduct_compile_move_or_alloc(compiler, &condExpr);
520 reduct_size_t jumpNext = reduct_compile_jump(compiler, REDUCT_OPCODE_JMPF, condReg);
521 reduct_expr_done(compiler, &condExpr);
522
523 reduct_compile_build_into_target(compiler, reduct_list_nth_item(compiler->reduct, &pair->list, 1), target);
524
525 if (jumpCount >= REDUCT_REGISTER_MAX)
526 {
527 REDUCT_ERROR_COMPILE(compiler, list, "too many clauses in cond, got %u", jumpCount);
528 }
529 jumpsEnd[jumpCount++] = reduct_compile_jump(compiler, REDUCT_OPCODE_JMP, 0);
530
531 reduct_compile_jump_patch(compiler, jumpNext);
532 }
533
534 if (target == REDUCT_REG_INVALID)
535 {
536 *out = REDUCT_EXPR_NIL(compiler);
537 return;
538 }
539
540 if (!alwaysHit)
541 {
542 reduct_expr_t nilConst = REDUCT_EXPR_NIL(compiler);
543 reduct_compile_move(compiler, target, &nilConst);
544 }
545
546 reduct_compile_jump_patch_list(compiler, jumpsEnd, jumpCount);
547
548 *out = REDUCT_EXPR_REG(target);
549}
550
552{
553 REDUCT_ASSERT(compiler != REDUCT_NULL);
554 REDUCT_ASSERT(list != REDUCT_NULL);
556
557 reduct_intrinsic_check_min_arity(compiler, list, 2, "match");
558
559 reduct_expr_t targetExpr = REDUCT_EXPR_NONE();
560 reduct_expr_build(compiler, reduct_list_nth_item(compiler->reduct, &list->list, 1), &targetExpr);
561
562 reduct_handle_t targetItem;
563 reduct_bool_t targetKnown = reduct_expr_get_item(compiler, &targetExpr, &targetItem);
565 reduct_reg_t resultReg = reduct_expr_get_reg(compiler, out);
566
568 reduct_size_t jumpCount = 0;
569
572 while (iter.index < list->length - 1 && reduct_list_iter_next(&iter, &h))
573 {
574 reduct_item_t* pair = reduct_intrinsic_get_pair(compiler, &h, "match");
576 reduct_expr_build(compiler, reduct_list_nth_item(compiler->reduct, &pair->list, 0), &valExpr);
577
578 reduct_handle_t valItem;
579 if (targetKnown && reduct_expr_get_item(compiler, &valExpr, &valItem))
580 {
581 reduct_bool_t cmpResult = REDUCT_FALSE;
582 if (reduct_fold_comparison(compiler->reduct, REDUCT_OPCODE_EQ, targetItem, valItem, &cmpResult))
583 {
584 reduct_expr_done(compiler, &valExpr);
585 if (!cmpResult)
586 {
587 continue;
588 }
589
591 resultReg);
592 reduct_expr_done(compiler, &targetExpr);
593 *out = REDUCT_EXPR_REG(resultReg);
594 return;
595 }
596 }
597
598 if (targetReg == REDUCT_REG_INVALID)
599 {
600 targetReg = reduct_compile_move_or_alloc(compiler, &targetExpr);
601 }
602
603 reduct_reg_t cmpResultReg = reduct_reg_alloc(compiler);
604 reduct_compile_binary(compiler, REDUCT_OPCODE_EQ, cmpResultReg, targetReg, &valExpr);
605 reduct_expr_done(compiler, &valExpr);
606
607 reduct_size_t jumpNext = reduct_compile_jump(compiler, REDUCT_OPCODE_JMPF, cmpResultReg);
608 reduct_reg_free(compiler, cmpResultReg);
609
610 reduct_compile_build_into_target(compiler, reduct_list_nth_item(compiler->reduct, &pair->list, 1), resultReg);
611 if (REDUCT_UNLIKELY(jumpCount >= REDUCT_REGISTER_MAX))
612 {
613 REDUCT_ERROR_COMPILE(compiler, list, "too many clauses in match, limit is %u", REDUCT_REGISTER_MAX);
614 }
615 jumpsEnd[jumpCount++] = reduct_compile_jump(compiler, REDUCT_OPCODE_JMP, 0);
616 reduct_compile_jump_patch(compiler, jumpNext);
617 }
618
619 reduct_compile_build_into_target(compiler, reduct_list_nth_item(compiler->reduct, &list->list, list->length - 1),
620 resultReg);
621
622 reduct_compile_jump_patch_list(compiler, jumpsEnd, jumpCount);
623
624 reduct_expr_done(compiler, &targetExpr);
625 *out = REDUCT_EXPR_REG(resultReg);
626}
627
629 reduct_opcode_t jumpOp)
630{
631 REDUCT_ASSERT(compiler != REDUCT_NULL);
632 REDUCT_ASSERT(list != REDUCT_NULL);
634
635 if (list->length < 2)
636 {
637 *out = REDUCT_EXPR_FALSE(compiler);
638 return;
639 }
640
641 reduct_reg_t targetHint = REDUCT_EXPR_GET_TARGET(out);
644 reduct_size_t jumpCount = 0;
645
647 REDUCT_LIST_FOR_EACH_AT(&h, &list->list, 1)
648 {
650 if (target != REDUCT_REG_INVALID)
651 {
652 argExpr = REDUCT_EXPR_TARGET(target);
653 }
654
655 reduct_expr_build(compiler, REDUCT_HANDLE_TO_ITEM(&h), &argExpr);
656
657 reduct_bool_t isTruthy;
658 if (reduct_expr_is_known_truthy(compiler, &argExpr, &isTruthy))
659 {
660 reduct_bool_t shortCircuits = (jumpOp == REDUCT_OPCODE_JMPT) ? isTruthy : !isTruthy;
661
662 if (shortCircuits || _iter.index == list->length)
663 {
664 if (target == REDUCT_REG_INVALID)
665 {
666 *out = argExpr;
667 return;
668 }
669
670 reduct_compile_move(compiler, target, &argExpr);
671 reduct_expr_done(compiler, &argExpr);
672 break;
673 }
674
675 reduct_expr_done(compiler, &argExpr);
676 continue;
677 }
678
679 if (target == REDUCT_REG_INVALID)
680 {
681 target = (targetHint != REDUCT_REG_INVALID) ? targetHint : reduct_reg_alloc(compiler);
682 }
683
684 if (argExpr.mode != REDUCT_MODE_REG || argExpr.reg != target)
685 {
686 reduct_compile_move(compiler, target, &argExpr);
687 reduct_expr_done(compiler, &argExpr);
688 }
689
690 if (_iter.index != list->length)
691 {
692 if (REDUCT_UNLIKELY(jumpCount >= REDUCT_REGISTER_MAX))
693 {
694 REDUCT_ERROR_COMPILE(compiler, list, "too many arguments for logical operator, limit is %u",
696 }
697 jumps[jumpCount++] = reduct_compile_jump(compiler, jumpOp, target);
698 }
699 }
700
701 reduct_compile_jump_patch_list(compiler, jumps, jumpCount);
702
703 *out = REDUCT_EXPR_REG(target);
704}
705
707{
708 reduct_intrinsic_and_or(compiler, list, out, REDUCT_OPCODE_JMPF);
709}
710
712{
713 reduct_intrinsic_and_or(compiler, list, out, REDUCT_OPCODE_JMPT);
714}
715
717{
718 REDUCT_ASSERT(compiler != REDUCT_NULL);
719 REDUCT_ASSERT(list != REDUCT_NULL);
721
722 reduct_intrinsic_check_arity(compiler, list, 1, "not");
723
724 reduct_reg_t target = reduct_expr_get_reg(compiler, out);
725
727 reduct_expr_build(compiler, reduct_list_nth_item(compiler->reduct, &list->list, 1), &argExpr);
728
729 reduct_bool_t isTruthy;
730 if (reduct_expr_is_known_truthy(compiler, &argExpr, &isTruthy))
731 {
732 reduct_expr_done(compiler, &argExpr);
733 *out = isTruthy ? REDUCT_EXPR_FALSE(compiler) : REDUCT_EXPR_TRUE(compiler);
734 return;
735 }
736
737 reduct_reg_t argReg = reduct_compile_move_or_alloc(compiler, &argExpr);
738 reduct_size_t jumpTrue = reduct_compile_jump(compiler, REDUCT_OPCODE_JMPT, argReg);
739 reduct_expr_done(compiler, &argExpr);
740
741 reduct_expr_t trueExpr = REDUCT_EXPR_TRUE(compiler);
742 reduct_compile_move(compiler, target, &trueExpr);
743
745
746 reduct_compile_jump_patch(compiler, jumpTrue);
747 reduct_expr_t falseExpr = REDUCT_EXPR_FALSE(compiler);
748 reduct_compile_move(compiler, target, &falseExpr);
749
750 reduct_compile_jump_patch(compiler, jumpEnd);
751
752 *out = REDUCT_EXPR_REG(target);
753}
754
757{
758 if (isFloat)
759 {
760 switch (op)
761 {
763 return reduct_atom_lookup_float(compiler->reduct, lf + rf);
765 return reduct_atom_lookup_float(compiler->reduct, lf - rf);
767 return reduct_atom_lookup_float(compiler->reduct, lf * rf);
769 return (rf == 0.0) ? REDUCT_NULL : reduct_atom_lookup_float(compiler->reduct, lf / rf);
770 default:
771 return REDUCT_NULL;
772 }
773 }
774 else
775 {
776 switch (op)
777 {
779 return reduct_atom_lookup_int(compiler->reduct, li + ri);
781 return reduct_atom_lookup_int(compiler->reduct, li - ri);
783 return reduct_atom_lookup_int(compiler->reduct, li * ri);
785 return (ri == 0) ? REDUCT_NULL : reduct_atom_lookup_int(compiler->reduct, li / ri);
787 return (ri == 0) ? REDUCT_NULL : reduct_atom_lookup_int(compiler->reduct, li % ri);
789 return reduct_atom_lookup_int(compiler->reduct, li & ri);
791 return reduct_atom_lookup_int(compiler->reduct, li | ri);
793 return reduct_atom_lookup_int(compiler->reduct, li ^ ri);
795 return (ri < 0 || ri >= 64) ? REDUCT_NULL : reduct_atom_lookup_int(compiler->reduct, li << ri);
797 return (ri < 0 || ri >= 64) ? REDUCT_NULL : reduct_atom_lookup_int(compiler->reduct, li >> ri);
798 default:
799 return REDUCT_NULL;
800 }
801 }
802}
803
805 reduct_expr_t* leftExpr, reduct_expr_t* rightExpr, reduct_expr_t* outExpr)
806{
807 REDUCT_ASSERT(compiler != REDUCT_NULL);
808 REDUCT_ASSERT(leftExpr != REDUCT_NULL);
809 REDUCT_ASSERT(rightExpr != REDUCT_NULL);
810
811 REDUCT_ASSERT(outExpr != REDUCT_NULL);
812 if (leftExpr->mode != REDUCT_MODE_CONST || rightExpr->mode != REDUCT_MODE_CONST)
813 {
814 return REDUCT_FALSE;
815 }
816
817 if (compiler->function->constants[leftExpr->constant].type != REDUCT_CONST_SLOT_ITEM ||
818 compiler->function->constants[rightExpr->constant].type != REDUCT_CONST_SLOT_ITEM)
819 {
820 return REDUCT_FALSE;
821 }
822
823 reduct_item_t* leftItem = compiler->function->constants[leftExpr->constant].item;
824 reduct_item_t* rightItem = compiler->function->constants[rightExpr->constant].item;
825
826 reduct_bool_t isFloat =
828
831 reduct_int64_t li = reduct_item_get_int(leftItem);
832 reduct_int64_t ri = reduct_item_get_int(rightItem);
833
834 reduct_atom_t* result = reduct_fold_binary_calc(compiler, opBase, lf, rf, li, ri, isFloat);
835 if (result == REDUCT_NULL)
836 {
837 return REDUCT_FALSE;
838 }
839
840 *outExpr = REDUCT_EXPR_CONST_ATOM(compiler, result);
841 return REDUCT_TRUE;
842}
843
845 reduct_opcode_t opBase)
846{
847 REDUCT_ASSERT(compiler != REDUCT_NULL);
848 REDUCT_ASSERT(list != REDUCT_NULL);
850
851 if (opBase == REDUCT_OPCODE_MOD || opBase == REDUCT_OPCODE_SHL || opBase == REDUCT_OPCODE_SHR)
852 {
853 reduct_intrinsic_check_arity(compiler, list, 2, "operator");
854 }
855 else if (opBase >= REDUCT_OPCODE_BAND && opBase <= REDUCT_OPCODE_BXOR)
856 {
857 reduct_intrinsic_check_min_arity(compiler, list, 2, "bitwise operator");
858 }
859 else
860 {
861 reduct_intrinsic_check_min_arity(compiler, list, 1, "arithmetic operator");
862 }
863
864 reduct_reg_t targetHint = REDUCT_EXPR_GET_TARGET(out);
865 reduct_expr_t leftExpr = REDUCT_EXPR_NONE();
866 reduct_expr_build(compiler, reduct_list_nth_item(compiler->reduct, &list->list, 1), &leftExpr);
867
868 if (list->length == 2)
869 {
870 if (opBase == REDUCT_OPCODE_SUB || opBase == REDUCT_OPCODE_DIV)
871 {
872 reduct_expr_t initialExpr =
873 (opBase == REDUCT_OPCODE_SUB) ? REDUCT_EXPR_INT(compiler, 0) : REDUCT_EXPR_INT(compiler, 1);
874 reduct_expr_t foldedExpr;
875 if (reduct_fold_binary_expr(compiler, opBase, &initialExpr, &leftExpr, &foldedExpr))
876 {
877 reduct_expr_done(compiler, &leftExpr);
878 *out = foldedExpr;
879 return;
880 }
881
882 reduct_reg_t initialReg = reduct_compile_move_or_alloc(compiler, &initialExpr);
883 reduct_reg_t target = (targetHint != REDUCT_REG_INVALID) ? targetHint : reduct_reg_alloc(compiler);
884 reduct_compile_binary(compiler, opBase, target, initialReg, &leftExpr);
885
886 reduct_expr_done(compiler, &leftExpr);
887 reduct_expr_done(compiler, &initialExpr);
888 *out = REDUCT_EXPR_REG(target);
889 return;
890 }
891
892 *out = leftExpr;
893 return;
894 }
895
896 reduct_bool_t hasAccumulator = REDUCT_FALSE;
899 while (reduct_list_iter_next(&iter, &h))
900 {
901 reduct_expr_t rightExpr = REDUCT_EXPR_NONE();
902 reduct_expr_build(compiler, REDUCT_HANDLE_TO_ITEM(&h), &rightExpr);
903
904 reduct_expr_t foldedExpr;
905 if (reduct_fold_binary_expr(compiler, opBase, &leftExpr, &rightExpr, &foldedExpr))
906 {
907 reduct_expr_done(compiler, &leftExpr);
908 reduct_expr_done(compiler, &rightExpr);
909 leftExpr = foldedExpr;
910 continue;
911 }
912
913 if (!hasAccumulator)
914 {
915 if (leftExpr.mode != REDUCT_MODE_REG)
916 {
917 reduct_compile_move_or_alloc(compiler, &leftExpr);
918 }
919
920 reduct_reg_t target = (targetHint != REDUCT_REG_INVALID) ? targetHint : reduct_reg_alloc(compiler);
921 reduct_compile_binary(compiler, opBase, target, leftExpr.reg, &rightExpr);
922 reduct_expr_done(compiler, &leftExpr);
923 leftExpr = REDUCT_EXPR_REG(target);
924 hasAccumulator = REDUCT_TRUE;
925 }
926 else
927 {
928 reduct_compile_binary(compiler, opBase, leftExpr.reg, leftExpr.reg, &rightExpr);
929 }
930
931 reduct_expr_done(compiler, &rightExpr);
932 }
933
934 *out = leftExpr;
935}
936
941
946
951
956
961
963 reduct_opcode_t op, reduct_expr_t rightExpr, const char* name)
964{
965 reduct_intrinsic_check_arity(compiler, list, 1, name);
966
967 reduct_expr_t leftExpr = REDUCT_EXPR_NONE();
968 reduct_expr_build(compiler, reduct_list_nth_item(compiler->reduct, &list->list, 1), &leftExpr);
969
970 reduct_expr_t foldedExpr;
971 if (reduct_fold_binary_expr(compiler, op, &leftExpr, &rightExpr, &foldedExpr))
972 {
973 reduct_expr_done(compiler, &leftExpr);
974 reduct_expr_done(compiler, &rightExpr);
975 *out = foldedExpr;
976 return;
977 }
978
979 reduct_reg_t target = reduct_expr_get_reg(compiler, out);
980 reduct_compile_binary(compiler, op, target, reduct_compile_move_or_alloc(compiler, &leftExpr), &rightExpr);
981 reduct_expr_done(compiler, &leftExpr);
982 reduct_expr_done(compiler, &rightExpr);
983 *out = REDUCT_EXPR_REG(target);
984}
985
987{
988 reduct_intrinsic_unary_op_generic(compiler, list, out, REDUCT_OPCODE_ADD, REDUCT_EXPR_INT(compiler, 1), "inc");
989}
990
992{
993 reduct_intrinsic_unary_op_generic(compiler, list, out, REDUCT_OPCODE_SUB, REDUCT_EXPR_INT(compiler, 1), "dec");
994}
995
1000
1005
1010
1012{
1013 REDUCT_ASSERT(compiler != REDUCT_NULL);
1014 REDUCT_ASSERT(list != REDUCT_NULL);
1015 REDUCT_ASSERT(out != REDUCT_NULL);
1016
1017 reduct_intrinsic_check_arity(compiler, list, 1, "bitwise not");
1018
1019 reduct_expr_t argExpr = REDUCT_EXPR_NONE();
1020 reduct_expr_build(compiler, reduct_list_nth_item(compiler->reduct, &list->list, 1), &argExpr);
1021
1022 if (argExpr.mode == REDUCT_MODE_CONST &&
1023 compiler->function->constants[argExpr.constant].type == REDUCT_CONST_SLOT_ITEM)
1024 {
1025 reduct_item_t* argItem = compiler->function->constants[argExpr.constant].item;
1026 if (argItem->flags & REDUCT_ITEM_FLAG_INT_SHAPED)
1027 {
1028 reduct_atom_t* result = reduct_atom_lookup_int(compiler->reduct, ~argItem->atom.integerValue);
1029 reduct_expr_done(compiler, &argExpr);
1030 *out = REDUCT_EXPR_CONST_ATOM(compiler, result);
1031 return;
1032 }
1033 }
1034
1035 reduct_reg_t target = reduct_expr_get_reg(compiler, out);
1036 reduct_compile_inst(compiler,
1037 REDUCT_INST_MAKE_ABC((reduct_opcode_t)(REDUCT_OPCODE_BNOT | argExpr.mode), target, 0, argExpr.value));
1038 reduct_expr_done(compiler, &argExpr);
1039 *out = REDUCT_EXPR_REG(target);
1040}
1041
1046
1051
1053 reduct_opcode_t opBase)
1054{
1055 REDUCT_ASSERT(compiler != REDUCT_NULL);
1056 REDUCT_ASSERT(list != REDUCT_NULL);
1057 REDUCT_ASSERT(out != REDUCT_NULL);
1058
1059 reduct_intrinsic_check_min_arity(compiler, list, 2, "comparison");
1060
1061 reduct_reg_t targetHint = REDUCT_EXPR_GET_TARGET(out);
1062 reduct_expr_t leftExpr = REDUCT_EXPR_NONE();
1063 reduct_expr_build(compiler, reduct_list_nth_item(compiler->reduct, &list->list, 1), &leftExpr);
1064
1067 reduct_size_t jumpCount = 0;
1068
1070 REDUCT_LIST_FOR_EACH_AT(&h, &list->list, 2)
1071 {
1072 reduct_expr_t rightExpr = REDUCT_EXPR_NONE();
1073 reduct_expr_build(compiler, REDUCT_HANDLE_TO_ITEM(&h), &rightExpr);
1074
1075 reduct_handle_t leftItem, rightItem;
1076 if (reduct_expr_get_item(compiler, &leftExpr, &leftItem) &&
1077 reduct_expr_get_item(compiler, &rightExpr, &rightItem))
1078 {
1079 reduct_bool_t cmpResult = REDUCT_FALSE;
1080 if (reduct_fold_comparison(compiler->reduct, opBase, leftItem, rightItem, &cmpResult))
1081 {
1082 if (cmpResult)
1083 {
1084 reduct_expr_done(compiler, &leftExpr);
1085 leftExpr = rightExpr;
1086 continue;
1087 }
1088 else
1089 {
1090 reduct_expr_done(compiler, &leftExpr);
1091 reduct_expr_done(compiler, &rightExpr);
1092
1093 if (jumpCount > 0)
1094 {
1095 reduct_expr_t falseExpr = REDUCT_EXPR_FALSE(compiler);
1096 reduct_compile_move(compiler, target, &falseExpr);
1097 reduct_compile_jump_patch_list(compiler, jumps, jumpCount);
1098 *out = REDUCT_EXPR_REG(target);
1099 }
1100 else
1101 {
1102 if (target != REDUCT_REG_INVALID)
1103 {
1104 reduct_reg_free(compiler, target);
1105 }
1106 *out = REDUCT_EXPR_FALSE(compiler);
1107 }
1108 return;
1109 }
1110 }
1111 }
1112
1113 if (target == REDUCT_REG_INVALID)
1114 {
1115 target = (targetHint != REDUCT_REG_INVALID) ? targetHint : reduct_reg_alloc(compiler);
1116 }
1117
1118 if (leftExpr.mode != REDUCT_MODE_REG)
1119 {
1120 reduct_compile_move_or_alloc(compiler, &leftExpr);
1121 }
1122
1123 reduct_compile_binary(compiler, opBase, target, leftExpr.reg, &rightExpr);
1124
1125 if (_iter.index != list->length)
1126 {
1127 if (jumpCount >= REDUCT_REGISTER_MAX)
1128 {
1129 REDUCT_ERROR_COMPILE(compiler, list, "comparison expects at most 256 arguments, got %u", jumpCount);
1130 }
1131 jumps[jumpCount++] = reduct_compile_jump(compiler, REDUCT_OPCODE_JMPF, target);
1132
1133 reduct_expr_done(compiler, &leftExpr);
1134 leftExpr = rightExpr;
1135 }
1136 else
1137 {
1138 reduct_expr_done(compiler, &leftExpr);
1139 reduct_expr_done(compiler, &rightExpr);
1140 leftExpr = REDUCT_EXPR_NONE();
1141 }
1142 }
1143
1144 reduct_expr_done(compiler, &leftExpr);
1145
1146 if (jumpCount > 0)
1147 {
1148 reduct_compile_jump_patch_list(compiler, jumps, jumpCount);
1149 *out = REDUCT_EXPR_REG(target);
1150 }
1151 else if (target == REDUCT_REG_INVALID)
1152 {
1153 *out = REDUCT_EXPR_TRUE(compiler);
1154 }
1155 else
1156 {
1157 *out = REDUCT_EXPR_REG(target);
1158 }
1159}
1160
1165
1170
1175
1180
1185
1190
1195
1200
1203
1209
1211
1218
1232
1241};
1242
1244 [REDUCT_INTRINSIC_NONE] = "",
1245 [REDUCT_INTRINSIC_QUOTE] = "quote",
1246 [REDUCT_INTRINSIC_LIST] = "list",
1247 [REDUCT_INTRINSIC_DO] = "do",
1248 [REDUCT_INTRINSIC_DEF] = "def",
1249 [REDUCT_INTRINSIC_LAMBDA] = "lambda",
1250 [REDUCT_INTRINSIC_THREAD] = "->",
1251 [REDUCT_INTRINSIC_IF] = "if",
1252 [REDUCT_INTRINSIC_COND] = "cond",
1253 [REDUCT_INTRINSIC_MATCH] = "match",
1254 [REDUCT_INTRINSIC_AND] = "and",
1255 [REDUCT_INTRINSIC_OR] = "or",
1256 [REDUCT_INTRINSIC_NOT] = "not",
1257 [REDUCT_INTRINSIC_ADD] = "+",
1258 [REDUCT_INTRINSIC_SUB] = "-",
1259 [REDUCT_INTRINSIC_MUL] = "*",
1260 [REDUCT_INTRINSIC_DIV] = "/",
1261 [REDUCT_INTRINSIC_MOD] = "%",
1262 [REDUCT_INTRINSIC_INC] = "++",
1263 [REDUCT_INTRINSIC_DEC] = "--",
1264 [REDUCT_INTRINSIC_SEQ] = "eq?",
1265 [REDUCT_INTRINSIC_SNEQ] = "ne?",
1266 [REDUCT_INTRINSIC_EQ] = "==",
1267 [REDUCT_INTRINSIC_NEQ] = "!=",
1268 [REDUCT_INTRINSIC_LT] = "<",
1269 [REDUCT_INTRINSIC_LE] = "<=",
1270 [REDUCT_INTRINSIC_GT] = ">",
1271 [REDUCT_INTRINSIC_GE] = ">=",
1272 [REDUCT_INTRINSIC_BAND] = "&",
1273 [REDUCT_INTRINSIC_BOR] = "|",
1274 [REDUCT_INTRINSIC_BXOR] = "^",
1275 [REDUCT_INTRINSIC_BNOT] = "~",
1276 [REDUCT_INTRINSIC_SHL] = "<<",
1277 [REDUCT_INTRINSIC_SHR] = ">>",
1278};
1279
1280#define REDUCT_INTRINSIC_NATIVE_ARITH(_name, _op, _identity) \
1281 static reduct_handle_t reduct_intrinsic_native_##_name(reduct_t* reduct, reduct_size_t argc, \
1282 reduct_handle_t* argv) \
1283 { \
1284 if (argc == 0) \
1285 { \
1286 return REDUCT_HANDLE_FROM_INT(_identity); \
1287 } \
1288 if (argc == 1) \
1289 { \
1290 reduct_handle_t res; \
1291 reduct_handle_t id = REDUCT_HANDLE_FROM_INT(_identity); \
1292 REDUCT_HANDLE_ARITHMETIC_FAST(reduct, &res, &id, &argv[0], _op); \
1293 return res; \
1294 } \
1295 reduct_handle_t res = argv[0]; \
1296 for (reduct_size_t i = 1; i < argc; i++) \
1297 { \
1298 REDUCT_HANDLE_ARITHMETIC_FAST(reduct, &res, &res, &argv[i], _op); \
1299 } \
1300 return res; \
1301 }
1302
1303#define REDUCT_INTRINSIC_NATIVE_LOGIC(_name, _short_circuit_truth) \
1304 static reduct_handle_t reduct_intrinsic_native_##_name(reduct_t* reduct, reduct_size_t argc, \
1305 reduct_handle_t* argv) \
1306 { \
1307 REDUCT_UNUSED(reduct); \
1308 if (argc == 0) \
1309 { \
1310 return REDUCT_HANDLE_FALSE(); \
1311 } \
1312 reduct_handle_t res = argv[0]; \
1313 for (reduct_size_t i = 0; i < argc; i++) \
1314 { \
1315 res = argv[i]; \
1316 if (REDUCT_HANDLE_IS_TRUTHY(&res) == (_short_circuit_truth)) \
1317 { \
1318 return res; \
1319 } \
1320 } \
1321 return res; \
1322 }
1323
1324#define REDUCT_INTRINSIC_NATIVE_BITWISE(_name, _op) \
1325 static reduct_handle_t reduct_intrinsic_native_##_name(reduct_t* reduct, reduct_size_t argc, \
1326 reduct_handle_t* argv) \
1327 { \
1328 reduct_error_check_min_arity(reduct, argc, 2, #_op); \
1329 reduct_int64_t res = reduct_get_int(reduct, &argv[0]); \
1330 for (reduct_size_t i = 1; i < argc; i++) \
1331 { \
1332 res _op## = reduct_get_int(reduct, &argv[i]); \
1333 } \
1334 return REDUCT_HANDLE_FROM_INT(res); \
1335 }
1336
1337#define REDUCT_INTRINSIC_NATIVE_COMPARE(_name, _op) \
1338 static reduct_handle_t reduct_intrinsic_native_##_name(reduct_t* reduct, reduct_size_t argc, \
1339 reduct_handle_t* argv) \
1340 { \
1341 if (argc < 2) \
1342 { \
1343 return REDUCT_HANDLE_TRUE(); \
1344 } \
1345 for (reduct_size_t i = 0; i < argc - 1; i++) \
1346 { \
1347 if (!(reduct_handle_compare(reduct, &argv[i], &argv[i + 1]) _op 0)) \
1348 { \
1349 return REDUCT_HANDLE_FALSE(); \
1350 } \
1351 } \
1352 return REDUCT_HANDLE_TRUE(); \
1353 }
1354
1355#define REDUCT_INTRINSIC_NATIVE_COMPARE_STRICT(_name, _expected) \
1356 static reduct_handle_t reduct_intrinsic_native_##_name(reduct_t* reduct, reduct_size_t argc, \
1357 reduct_handle_t* argv) \
1358 { \
1359 if (argc < 2) \
1360 { \
1361 return REDUCT_HANDLE_TRUE(); \
1362 } \
1363 for (reduct_size_t i = 0; i < argc - 1; i++) \
1364 { \
1365 if (reduct_handle_is_equal(reduct, &argv[i], &argv[i + 1]) != (_expected)) \
1366 { \
1367 return REDUCT_HANDLE_FALSE(); \
1368 } \
1369 } \
1370 return REDUCT_HANDLE_TRUE(); \
1371 }
1372
1377
1381
1388
1391
1394
1396{
1397 reduct_list_t* list = reduct_list_new(reduct);
1398 for (reduct_size_t i = 0; i < argc; i++)
1399 {
1400 reduct_list_append(reduct, list, argv[i]);
1401 }
1402 return REDUCT_HANDLE_FROM_LIST(list);
1403}
1404
1406{
1407 reduct_error_check_arity(reduct, argc, 2, "%");
1408 reduct_promotion_t prom;
1409 reduct_handle_promote(reduct, &argv[0], &argv[1], &prom);
1410 if (prom.type != REDUCT_PROMOTION_TYPE_INT)
1411 {
1412 REDUCT_ERROR_RUNTIME(reduct, "%% expects integer arguments");
1413 }
1414 if (prom.b.intVal == 0)
1415 {
1416 REDUCT_ERROR_RUNTIME(reduct, "modulo by zero");
1417 }
1418 return REDUCT_HANDLE_FROM_INT(prom.a.intVal % prom.b.intVal);
1419}
1420
1422{
1423 reduct_error_check_arity(reduct, argc, 1, "++");
1424 reduct_handle_t res;
1426 REDUCT_HANDLE_ARITHMETIC_FAST(reduct, &res, &argv[0], &one, +);
1427 return res;
1428}
1429
1431{
1432 reduct_error_check_arity(reduct, argc, 1, "--");
1433 reduct_handle_t res;
1435 REDUCT_HANDLE_ARITHMETIC_FAST(reduct, &res, &argv[0], &one, -);
1436 return res;
1437}
1438
1440{
1441 reduct_error_check_arity(reduct, argc, 1, "~");
1442 return REDUCT_HANDLE_FROM_INT(~reduct_get_int(reduct, &argv[0]));
1443}
1444
1446{
1447 reduct_error_check_arity(reduct, argc, 2, "<<");
1448 reduct_int64_t left = reduct_get_int(reduct, &argv[0]);
1449 reduct_int64_t right = reduct_get_int(reduct, &argv[1]);
1450 if (right < 0 || right >= 64)
1451 {
1452 REDUCT_ERROR_RUNTIME(reduct, "shift amount out of range");
1453 }
1454 return REDUCT_HANDLE_FROM_INT(left << right);
1455}
1456
1458{
1459 reduct_error_check_arity(reduct, argc, 2, ">>");
1460 reduct_int64_t left = reduct_get_int(reduct, &argv[0]);
1461 reduct_int64_t right = reduct_get_int(reduct, &argv[1]);
1462 if (right < 0 || right >= 64)
1463 {
1464 REDUCT_ERROR_RUNTIME(reduct, "shift amount out of range");
1465 }
1466 return REDUCT_HANDLE_FROM_INT(left >> right);
1467}
1468
1470{
1471 if (argc == 0)
1472 {
1473 return reduct_handle_nil(reduct);
1474 }
1475 return argv[argc - 1];
1476}
1477
1483
1487 [REDUCT_INTRINSIC_AND] = reduct_intrinsic_native_and,
1488 [REDUCT_INTRINSIC_OR] = reduct_intrinsic_native_or,
1490 [REDUCT_INTRINSIC_ADD] = reduct_intrinsic_native_add,
1491 [REDUCT_INTRINSIC_SUB] = reduct_intrinsic_native_sub,
1492 [REDUCT_INTRINSIC_MUL] = reduct_intrinsic_native_mul,
1493 [REDUCT_INTRINSIC_DIV] = reduct_intrinsic_native_div,
1497 [REDUCT_INTRINSIC_BAND] = reduct_intrinsic_native_band,
1498 [REDUCT_INTRINSIC_BOR] = reduct_intrinsic_native_bor,
1499 [REDUCT_INTRINSIC_BXOR] = reduct_intrinsic_native_bxor,
1503 [REDUCT_INTRINSIC_EQ] = reduct_intrinsic_native_eq,
1504 [REDUCT_INTRINSIC_NEQ] = reduct_intrinsic_native_neq,
1505 [REDUCT_INTRINSIC_SEQ] = reduct_intrinsic_native_seq,
1506 [REDUCT_INTRINSIC_SNEQ] = reduct_intrinsic_native_sneq,
1507 [REDUCT_INTRINSIC_LT] = reduct_intrinsic_native_lt,
1508 [REDUCT_INTRINSIC_LE] = reduct_intrinsic_native_le,
1509 [REDUCT_INTRINSIC_GT] = reduct_intrinsic_native_gt,
1510 [REDUCT_INTRINSIC_GE] = reduct_intrinsic_native_ge,
1511};
1512
1513static inline void reduct_intrinsic_register(reduct_t* reduct, reduct_intrinsic_t intrinsic)
1514{
1515 REDUCT_ASSERT(reduct != REDUCT_NULL);
1516 REDUCT_ASSERT(intrinsic > REDUCT_INTRINSIC_NONE && intrinsic < REDUCT_INTRINSIC_MAX);
1517
1518 const char* str = reductIntrinsics[intrinsic];
1519 reduct_size_t len = REDUCT_STRLEN(str);
1520 reduct_atom_t* atom = reduct_atom_lookup(reduct, str, len, REDUCT_ATOM_LOOKUP_NONE);
1521 atom->intrinsic = intrinsic;
1522 atom->native = reductIntrinsicNatives[intrinsic];
1523 reduct_item_t* item = REDUCT_CONTAINER_OF(atom, reduct_item_t, atom);
1525 if (atom->native != REDUCT_NULL)
1526 {
1528 }
1530 REDUCT_GC_RETAIN_ITEM(reduct, item);
1531}
1532
1534{
1535 REDUCT_ASSERT(reduct != REDUCT_NULL);
1536
1538 {
1540 }
1541}
1542
1543#endif
Bytecode compilation.
#define REDUCT_STRLEN(s)
Definition defs.h:38
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
#define REDUCT_CONTAINER_OF(_ptr, _type, _member)
Container of macro.
Definition defs.h:184
int64_t reduct_int64_t
Definition defs.h:92
reduct_uint64_t reduct_handle_t
Handle type.
Definition defs.h:189
uint32_t reduct_uint32_t
Definition defs.h:95
double reduct_float_t
Definition defs.h:102
#define REDUCT_ASSERT(_cond)
Definition defs.h:25
uint8_t reduct_uint8_t
Definition defs.h:99
#define REDUCT_API
Definition defs.h:7
uint16_t reduct_uint16_t
Definition defs.h:97
#define REDUCT_NULL
Definition defs.h:23
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.
REDUCT_API reduct_atom_t * reduct_atom_lookup_int(struct reduct *reduct, reduct_int64_t value)
Lookup an atom by integer value.
REDUCT_API reduct_atom_t * reduct_atom_lookup_float(struct reduct *reduct, reduct_float_t value)
Lookup an atom by float value.
@ REDUCT_ATOM_LOOKUP_NONE
No flags.
Definition atom.h:39
static void reduct_compile_jump_patch(reduct_compiler_t *compiler, reduct_size_t pos)
Patch a previously emitted jump instruction to point to the current instruction.
Definition compile.h:481
reduct_const_t constant
Constant index.
Definition compile.h:33
#define REDUCT_EXPR_CONST_ITEM(_compiler, _item)
Create a REDUCT_MODE_CONST mode expression for a specific item.
Definition compile.h:207
#define REDUCT_EXPR_GET_TARGET(_expr)
Get the target register index from an expression, or -1 if no target is specified.
Definition compile.h:269
REDUCT_API reduct_local_t * reduct_local_add_arg(reduct_compiler_t *compiler, reduct_atom_t *name)
Add a function argument local to the compiler context.
REDUCT_API void reduct_reg_free(reduct_compiler_t *compiler, reduct_reg_t reg)
Free a register.
reduct_mode_t mode
Expression mode.
Definition compile.h:29
static void reduct_compile_capture(reduct_compiler_t *compiler, reduct_reg_t closureReg, reduct_uint32_t slot, reduct_expr_t *expr)
Emits a REDUCT_OPCODE_CAPTURE instruction.
Definition compile.h:672
#define REDUCT_EXPR_NIL(_compiler)
Create a REDUCT_MODE_CONST mode expression for the nil constant.
Definition compile.h:252
static void reduct_expr_done(reduct_compiler_t *compiler, reduct_expr_t *expr)
Free resources associated with an expression descriptor.
Definition compile.h:295
REDUCT_API void reduct_expr_build(reduct_compiler_t *compiler, reduct_item_t *item, reduct_expr_t *out)
Compiles a single Reduct item into an expression descriptor.
reduct_uint16_t localCount
The amount of local variables.
Definition compile.h:56
REDUCT_API reduct_local_t * reduct_local_def(reduct_compiler_t *compiler, reduct_atom_t *name)
Define a new local variable.
static void reduct_compile_jump_patch_list(reduct_compiler_t *compiler, reduct_size_t *jumps, reduct_size_t count)
Patch a list of jump instructions to point to the current instruction.
Definition compile.h:495
static void reduct_compile_binary(reduct_compiler_t *compiler, reduct_opcode_t opBase, reduct_reg_t target, reduct_reg_t left, reduct_expr_t *right)
Emits a comparison, arithmetic or bitwise instruction.
Definition compile.h:641
REDUCT_API void reduct_local_def_done(reduct_compiler_t *compiler, reduct_local_t *local, reduct_expr_t *expr)
Finalize a local variable definition with its value expression.
#define REDUCT_EXPR_TRUE(_compiler)
Create a REDUCT_MODE_CONST mode expression for the true constant.
Definition compile.h:234
static void reduct_compile_inst(reduct_compiler_t *compiler, reduct_inst_t inst)
Emits an instruction to the current function.
Definition compile.h:402
static void reduct_compile_return(reduct_compiler_t *compiler, reduct_expr_t *expr)
Emits a REDUCT_OPCODE_RET instruction.
Definition compile.h:533
REDUCT_API void reduct_reg_free_range(reduct_compiler_t *compiler, reduct_reg_t start, reduct_uint32_t count)
Free a range of registers.
reduct_expr_t expr
The expression representing the local's value.
Definition compile.h:44
reduct_reg_t reg
Register index.
Definition compile.h:32
#define REDUCT_EXPR_CONST_ATOM(_compiler, _atom)
Create a REDUCT_MODE_CONST mode expression for a specific atom.
Definition compile.h:217
static reduct_size_t reduct_compile_jump(reduct_compiler_t *compiler, reduct_opcode_t op, reduct_reg_t a)
Emits a jump instruction without a target offset.
Definition compile.h:467
reduct_t * reduct
The Reduct structure.
Definition compile.h:54
#define REDUCT_EXPR_TARGET(_reg)
Create a REDUCT_MODE_TARGET mode expression.
Definition compile.h:227
static void reduct_compile_closure(reduct_compiler_t *compiler, reduct_reg_t target, reduct_const_t funcConst)
Emits a REDUCT_OPCODE_CLOSURE instruction.
Definition compile.h:658
#define REDUCT_EXPR_INT(_compiler, _val)
Create a REDUCT_MODE_CONST mode expression for an integer.
Definition compile.h:262
static void reduct_compile_call(reduct_compiler_t *compiler, reduct_reg_t target, reduct_expr_t *callable, reduct_uint32_t arity)
Emits a REDUCT_OPCODE_CALL instruction, that returns its result in the target register.
Definition compile.h:429
static reduct_reg_t reduct_compile_move_or_alloc(reduct_compiler_t *compiler, reduct_expr_t *expr)
Emits a move instruction or allocates a new register if the expression is not already in a register.
Definition compile.h:511
REDUCT_API void reduct_local_pop(reduct_compiler_t *compiler, reduct_uint16_t toCount, reduct_expr_t *result)
Pop local variables from the stack, releasing their registers if they are no longer used.
static void reduct_compile_list(reduct_compiler_t *compiler, reduct_reg_t target)
Emits a REDUCT_OPCODE_LIST instruction, that creates a list in the target register.
Definition compile.h:415
#define REDUCT_EXPR_NONE()
Create a REDUCT_MODE_NONE mode expression.
Definition compile.h:185
reduct_uint16_t value
Raw union value.
Definition compile.h:31
reduct_function_t * function
The function being compiled.
Definition compile.h:55
REDUCT_API void reduct_compiler_init(reduct_compiler_t *compiler, reduct_t *reduct, reduct_function_t *function, reduct_compiler_t *enclosing)
Initialize a compiler context.
REDUCT_API reduct_reg_t reduct_reg_alloc(reduct_compiler_t *compiler)
Allocate a new register.
REDUCT_API void reduct_compiler_deinit(reduct_compiler_t *compiler)
Deinitialize a compiler context.
static void reduct_compile_move(reduct_compiler_t *compiler, reduct_reg_t target, reduct_expr_t *expr)
Emits a REDUCT_OPCODE_MOVE instruction, that moves the value of the source expression to the target r...
Definition compile.h:447
#define REDUCT_LOCAL_IS_DEFINED(_local)
Check if a local variable has finished being defined.
Definition compile.h:347
#define REDUCT_EXPR_FALSE(_compiler)
Create a REDUCT_MODE_CONST mode expression for the false constant.
Definition compile.h:243
static void reduct_compile_append(reduct_compiler_t *compiler, reduct_reg_t target, reduct_expr_t *expr)
Emits an REDUCT_OPCODE_APPEND instruction.
Definition compile.h:623
static reduct_reg_t reduct_expr_get_reg(reduct_compiler_t *compiler, reduct_expr_t *out)
Allocate a new register, favoring the output expression's target if provided.
Definition compile.h:312
REDUCT_API reduct_reg_t reduct_reg_alloc_range(reduct_compiler_t *compiler, reduct_uint32_t count)
Allocate a range of registers.
#define REDUCT_EXPR_REG(_reg)
Create a REDUCT_MODE_REG mode expression.
Definition compile.h:192
REDUCT_API reduct_local_t * reduct_local_lookup(reduct_compiler_t *compiler, reduct_atom_t *name)
Look up a local by name and return its expression.
#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_check_arity(struct reduct *reduct, reduct_size_t argc, reduct_size_t expected, const char *name)
Check the arity of a native function call.
#define REDUCT_ERROR_COMPILE(_compiler, _item,...)
Throw a compile error using the jump buffer in the error structure.
Definition error.h:162
reduct_uint16_t reduct_const_t
Constant index type.
Definition function.h:71
REDUCT_API reduct_function_t * reduct_function_new(struct reduct *reduct)
Create a new function.
#define REDUCT_CONST_SLOT_ITEM(_item)
Create a constant slot containing an item.
Definition function.h:57
REDUCT_API reduct_const_t reduct_function_lookup_constant(struct reduct *reduct, reduct_function_t *func, reduct_const_slot_t *slot)
Get the index of a constant in a function's constant template, adding it if it doesn't exist.
#define REDUCT_GC_RETAIN_ITEM(_reduct, _item)
Retain a item, preventing it from being collected by the GC.
Definition gc.h:56
#define REDUCT_HANDLE_FALSE()
Constant false handle.
Definition handle.h:267
#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 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.
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_FROM_ITEM(_ptr)
Create a handle from an item pointer.
Definition handle.h:76
#define REDUCT_HANDLE_IS_TRUTHY(_handle)
Check if a handle is truthy.
Definition handle.h:338
REDUCT_API reduct_int64_t reduct_handle_compare(struct reduct *reduct, reduct_handle_t *a, reduct_handle_t *b)
Compare two items for ordering (less than, equal, or greater than).
#define REDUCT_HANDLE_TRUE()
Constant true handle.
Definition handle.h:269
#define REDUCT_HANDLE_ARITHMETIC_FAST(_reduct, _a, _b, _c, _op)
Perform a arithmetic operation on two handles with a fast path for integers and floats.
Definition handle.h:303
@ REDUCT_PROMOTION_TYPE_INT
Definition handle.h:374
#define REDUCT_REG_INVALID
Invalid register value.
Definition inst.h:92
#define REDUCT_INST_MAKE_ABC(_op, _a, _b, _c)
Create an instruction with opcode, A, B, and C operands.
Definition inst.h:133
reduct_opcode_t
Opcode enumeration.
Definition inst.h:49
reduct_uint16_t reduct_reg_t
Register type.
Definition inst.h:87
#define REDUCT_REGISTER_MAX
The max number of registers per function frame.
Definition inst.h:108
@ REDUCT_MODE_REG
Register operand mode.
Definition inst.h:40
@ REDUCT_MODE_NONE
Invalid mode.
Definition inst.h:38
@ REDUCT_MODE_CONST
Constant operand mode.
Definition inst.h:41
@ 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_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_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_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_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_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_LE
(A, B, C) If R(B) <= R/K(C) store true in R(A), else false.
Definition inst.h:65
@ REDUCT_OPCODE_BXOR
(A, B, C) R(A) = R(B) ^ R/K(C)
Definition inst.h:75
@ 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_INTRINSIC_BOR
Bitwise Or.
Definition intrinsic.h:51
#define REDUCT_INTRINSIC_SHL
Bitwise Shift Left.
Definition intrinsic.h:54
#define REDUCT_INTRINSIC_INC
Inc.
Definition intrinsic.h:48
#define REDUCT_INTRINSIC_THREAD
Thread.
Definition intrinsic.h:35
reduct_intrinsic_handler_t reductIntrinsicHandlers[REDUCT_INTRINSIC_MAX]
Intrinsic handler functions array.
#define REDUCT_INTRINSIC_ADD
Add.
Definition intrinsic.h:43
#define REDUCT_INTRINSIC_NONE
None.
Definition intrinsic.h:30
#define REDUCT_INTRINSIC_BAND
Bitwise And.
Definition intrinsic.h:50
const char * reductIntrinsics[REDUCT_INTRINSIC_MAX]
Intrinsic names array.
#define REDUCT_INTRINSIC_OR
Or.
Definition intrinsic.h:41
#define REDUCT_INTRINSIC_MOD
Mod.
Definition intrinsic.h:47
#define REDUCT_INTRINSIC_COND
Cond.
Definition intrinsic.h:38
#define REDUCT_INTRINSIC_AND
And.
Definition intrinsic.h:40
#define REDUCT_INTRINSIC_DEF
Def.
Definition intrinsic.h:36
#define REDUCT_INTRINSIC_MAX
The amount of intrinsics.
Definition intrinsic.h:64
#define REDUCT_INTRINSIC_GE
Greater Equal.
Definition intrinsic.h:63
#define REDUCT_INTRINSIC_IF
If.
Definition intrinsic.h:37
#define REDUCT_INTRINSIC_BXOR
Bitwise Xor.
Definition intrinsic.h:52
#define REDUCT_INTRINSIC_NOT
Not.
Definition intrinsic.h:42
#define REDUCT_INTRINSIC_DO
Do.
Definition intrinsic.h:33
#define REDUCT_INTRINSIC_NEQ
Not Equal.
Definition intrinsic.h:57
#define REDUCT_INTRINSIC_LIST
List.
Definition intrinsic.h:32
#define REDUCT_INTRINSIC_SEQ
Strict Equal.
Definition intrinsic.h:58
#define REDUCT_INTRINSIC_DIV
Div.
Definition intrinsic.h:46
#define REDUCT_INTRINSIC_EQ
Equal.
Definition intrinsic.h:56
#define REDUCT_INTRINSIC_LAMBDA
Lambda.
Definition intrinsic.h:34
reduct_native_fn reductIntrinsicNatives[REDUCT_INTRINSIC_MAX]
Intrinsic native functions array.
reduct_uint8_t reduct_intrinsic_t
Intrinsic types.
Definition intrinsic.h:28
#define REDUCT_INTRINSIC_DEC
Dec.
Definition intrinsic.h:49
#define REDUCT_INTRINSIC_LT
Less.
Definition intrinsic.h:60
#define REDUCT_INTRINSIC_SUB
Sub.
Definition intrinsic.h:44
#define REDUCT_INTRINSIC_LE
Less Equal.
Definition intrinsic.h:61
#define REDUCT_INTRINSIC_GT
Greater.
Definition intrinsic.h:62
#define REDUCT_INTRINSIC_BNOT
Bitwise Not.
Definition intrinsic.h:53
#define REDUCT_INTRINSIC_MATCH
Match.
Definition intrinsic.h:39
void(* reduct_intrinsic_handler_t)(struct reduct_compiler *compiler, struct reduct_item *expr, struct reduct_expr *out)
Intrinsic handler function type.
Definition intrinsic.h:70
#define REDUCT_INTRINSIC_QUOTE
Quote.
Definition intrinsic.h:31
#define REDUCT_INTRINSIC_MUL
Mul.
Definition intrinsic.h:45
#define REDUCT_INTRINSIC_SHR
Bitwise Shift Right.
Definition intrinsic.h:55
#define REDUCT_INTRINSIC_SNEQ
Strict Not Equal.
Definition intrinsic.h:59
#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_ATOM
An atom.
Definition item.h:27
REDUCT_API reduct_float_t reduct_item_get_float(reduct_item_t *item)
Get the float value of an item if it is number shaped.
Definition item_impl.h:126
REDUCT_API reduct_int64_t reduct_item_get_int(reduct_item_t *item)
Get the integer value of an item if it is number shaped.
Definition item_impl.h:113
#define REDUCT_ITEM_FLAG_INT_SHAPED
Item is an integer shaped atom.
Definition item.h:39
#define REDUCT_ITEM_FLAG_FLOAT_SHAPED
Item is a float shaped atom.
Definition item.h:40
#define REDUCT_ITEM_FLAG_NATIVE
Item is an atom and a native function.
Definition item.h:42
#define REDUCT_ITEM_FLAG_INTRINSIC
Item is an atom and a intrinsic.
Definition item.h:41
reduct_handle_t(* reduct_native_fn)(struct reduct *reduct, reduct_size_t argc, reduct_handle_t *argv)
Native function pointer type.
Definition native.h:26
REDUCT_API reduct_handle_t reduct_get_int(struct reduct *reduct, reduct_handle_t *handle)
Intrinsic management.
void reduct_intrinsic_strict_not_equal(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_do(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
#define REDUCT_INTRINSIC_NATIVE_COMPARE(_name, _op)
static void reduct_intrinsic_and_or(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out, reduct_opcode_t jumpOp)
#define REDUCT_INTRINSIC_NATIVE_LOGIC(_name, _short_circuit_truth)
void reduct_intrinsic_bit_not(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static reduct_bool_t reduct_fold_comparison(reduct_t *reduct, reduct_opcode_t opBase, reduct_handle_t left, reduct_handle_t right, reduct_bool_t *result)
void reduct_intrinsic_inc(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static void reduct_intrinsic_check_min_arity(reduct_compiler_t *compiler, reduct_item_t *list, reduct_size_t min, const char *name)
static reduct_bool_t reduct_fold_binary_expr(reduct_compiler_t *compiler, reduct_opcode_t opBase, reduct_expr_t *leftExpr, reduct_expr_t *rightExpr, reduct_expr_t *outExpr)
void reduct_intrinsic_list(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static reduct_handle_t reduct_intrinsic_native_not(reduct_t *reduct, reduct_size_t argc, reduct_handle_t *argv)
static reduct_handle_t reduct_intrinsic_native_inc(reduct_t *reduct, reduct_size_t argc, reduct_handle_t *argv)
void reduct_intrinsic_quote(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static reduct_handle_t reduct_intrinsic_native_list(reduct_t *reduct, reduct_size_t argc, reduct_handle_t *argv)
static reduct_atom_t * reduct_fold_binary_calc(reduct_compiler_t *compiler, reduct_opcode_t op, reduct_float_t lf, reduct_float_t rf, reduct_int64_t li, reduct_int64_t ri, reduct_bool_t isFloat)
static reduct_handle_t reduct_intrinsic_native_do(reduct_t *reduct, reduct_size_t argc, reduct_handle_t *argv)
static void reduct_intrinsic_register(reduct_t *reduct, reduct_intrinsic_t intrinsic)
void reduct_intrinsic_bit_shl(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_not(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static reduct_item_t * reduct_intrinsic_get_pair(reduct_compiler_t *compiler, reduct_handle_t *h, const char *name)
void reduct_intrinsic_def(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static reduct_handle_t reduct_intrinsic_native_shl(reduct_t *reduct, reduct_size_t argc, reduct_handle_t *argv)
void reduct_intrinsic_if(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static void reduct_compile_build_into_target(reduct_compiler_t *compiler, reduct_item_t *item, reduct_reg_t target)
void reduct_intrinsic_strict_equal(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static void reduct_intrinsic_check_arity_range(reduct_compiler_t *compiler, reduct_item_t *list, reduct_size_t min, reduct_size_t max, const char *name)
static reduct_bool_t reduct_expr_get_item(reduct_compiler_t *compiler, reduct_expr_t *expr, reduct_handle_t *outItem)
REDUCT_API void reduct_intrinsic_register_all(reduct_t *reduct)
#define REDUCT_INTRINSIC_NATIVE_BITWISE(_name, _op)
void reduct_intrinsic_or(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_greater(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static void reduct_intrinsic_check_arity(reduct_compiler_t *compiler, reduct_item_t *list, reduct_size_t expected, const char *name)
void reduct_intrinsic_greater_equal(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static void reduct_intrinsic_comparison_generic(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out, reduct_opcode_t opBase)
void reduct_intrinsic_block_generic(reduct_compiler_t *compiler, reduct_item_t *list, reduct_uint32_t startIdx, reduct_expr_t *out)
void reduct_intrinsic_less(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_bit_and(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_add(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_bit_or(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_less_equal(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
#define REDUCT_INTRINSIC_NATIVE_COMPARE_STRICT(_name, _expected)
#define REDUCT_INTRINSIC_NATIVE_ARITH(_name, _op, _identity)
void reduct_intrinsic_sub(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static reduct_handle_t reduct_intrinsic_native_dec(reduct_t *reduct, reduct_size_t argc, reduct_handle_t *argv)
void reduct_intrinsic_div(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_dec(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_bit_shr(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static reduct_handle_t reduct_intrinsic_native_bnot(reduct_t *reduct, reduct_size_t argc, reduct_handle_t *argv)
void reduct_intrinsic_lambda(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static reduct_handle_t reduct_intrinsic_native_mod(reduct_t *reduct, reduct_size_t argc, reduct_handle_t *argv)
static void reduct_intrinsic_unary_op_generic(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out, reduct_opcode_t op, reduct_expr_t rightExpr, const char *name)
void reduct_intrinsic_binary_generic(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out, reduct_opcode_t opBase)
void reduct_intrinsic_match(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_bit_xor(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_equal(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_not_equal(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_thread(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static reduct_bool_t reduct_expr_is_known_truthy(reduct_compiler_t *compiler, reduct_expr_t *expr, reduct_bool_t *isTruthy)
void reduct_intrinsic_and(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_cond(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
static reduct_handle_t reduct_intrinsic_native_shr(reduct_t *reduct, reduct_size_t argc, reduct_handle_t *argv)
void reduct_intrinsic_mul(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
void reduct_intrinsic_mod(reduct_compiler_t *compiler, reduct_item_t *list, reduct_expr_t *out)
Item management.
#define REDUCT_LIST_ITER_AT(_list, _start)
Create a initializer for a list iterator start at a specific index.
Definition list.h:164
#define REDUCT_LIST_FOR_EACH_AT(_handle, _list, _start)
Macro for iterating over elements in a list starting from a specific index.
Definition list.h:191
REDUCT_API void reduct_list_append(struct reduct *reduct, reduct_list_t *list, reduct_handle_t val)
Append an element to the list.
#define REDUCT_LIST_FOR_EACH(_handle, _list)
Macro for iterating over all elements in a list.
Definition list.h:181
REDUCT_API reduct_bool_t reduct_list_iter_next(reduct_list_iter_t *iter, reduct_handle_t *out)
Get the next element from the iterator.
Definition list_impl.h:255
REDUCT_API reduct_list_t * reduct_list_new(struct reduct *reduct)
Create a new editable list.
REDUCT_API struct reduct_item * reduct_list_nth_item(struct reduct *reduct, reduct_list_t *list, reduct_size_t index)
Get the nth element of the list as an item.
Definition list_impl.h:172
Atom structure.
Definition atom.h:48
reduct_native_fn native
Native function, item must have REDUCT_ITEM_FLAG_NATIVE.
Definition atom.h:57
reduct_int64_t integerValue
Pre-computed integer value, item must have REDUCT_ITEM_FLAG_INT_SHAPED.
Definition atom.h:55
char * string
Pointer to the string.
Definition atom.h:53
reduct_intrinsic_t intrinsic
Cached intrinsic, item must have REDUCT_ITEM_FLAG_INTRINSIC.
Definition atom.h:52
Compiler structure.
Definition compile.h:52
Constant slot.
Definition function.h:43
reduct_const_slot_type_t type
The type of the constant slot.
Definition function.h:44
struct reduct_item * item
The item contained in the constant slot.
Definition function.h:47
struct reduct_atom * capture
The name of the variable to be captured.
Definition function.h:48
Expression descriptor structure.
Definition compile.h:28
Compiled function structure.
Definition function.h:78
reduct_const_slot_t * constants
The array of constant slots forming the constant template.
Definition function.h:83
reduct_uint16_t constantCount
Number of constants.
Definition function.h:84
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_uint32_t length
Common length for the item. (Stored in the union to save space due to padding rules....
Definition item.h:65
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 iterator structure.
Definition list.h:139
reduct_size_t index
Definition list.h:141
List structure.
Definition list.h:48
Local structure.
Definition compile.h:42
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