Reduct  v1.0.4-3-gdaf0d70
A functional and immutable language.
Loading...
Searching...
No Matches
compile.h
Go to the documentation of this file.
1#include "defs.h"
2#ifndef REDUCT_COMPILE_H
3#define REDUCT_COMPILE_H 1
4
5#include "core.h"
6#include "function.h"
7#include "gc.h"
8#include "inst.h"
9#include "item.h"
10#include "list.h"
11
12/**
13 * @file compile.h
14 * @brief Bytecode compilation.
15 * @defgroup compile Compilation
16 *
17 * The compilation process converts S-expressions into register-based bytecode that can be executed by the Reduct
18 * virtual machine.
19 *
20 * @{
21 */
22
23/**
24 * @brief Expression descriptor structure.
25 * @struct reduct_expr_t
26 */
27typedef struct reduct_expr
28{
29 reduct_mode_t mode; ///< Expression mode.
30 union {
31 reduct_uint16_t value; ///< Raw union value
32 reduct_reg_t reg; ///< Register index
33 reduct_const_t constant; ///< Constant index
34 };
36
37/**
38 * @brief Local structure.
39 * @struct reduct_local_t
40 */
41typedef struct reduct_local
42{
43 reduct_atom_t* name; ///< The name of the local variable.
44 reduct_expr_t expr; ///< The expression representing the local's value.
46
47/**
48 * @brief Compiler structure.
49 * @struct reduct_compiler_t
50 */
51typedef struct reduct_compiler
52{
53 struct reduct_compiler* enclosing; ///< The enclosing compiler context, or `REDUCT_NULL`.
54 reduct_t* reduct; ///< The Reduct structure.
55 reduct_function_t* function; ///< The function being compiled.
56 reduct_uint16_t localCount; ///< The amount of local variables.
57 reduct_uint64_t regAlloc[REDUCT_REGISTER_MAX / 64]; ///< Bitmask of allocated registers.
58 reduct_uint64_t regLocal[REDUCT_REGISTER_MAX / 64]; ///< Bitmask of registers used by locals.
59 reduct_local_t locals[REDUCT_REGISTER_MAX]; ///< The local variables.
60 reduct_item_t* lastItem; ///< The last item processed by the compiler, used for error reporting.
62
63/**
64 * @brief Compiles a Reduct AST into a callable bytecode function.
65 *
66 * @warning The jump buffer must have been set using `REDUCT_CATCH` before calling this function.
67 *
68 * @param reduct The Reduct structure.
69 * @param ast The root AST item to compile (usually a list of expressions).
70 * @return A pointer to the compiled function.
71 */
73
74/**
75 * @brief Initialize a compiler context.
76 *
77 * @param compiler The compiler context to initialize.
78 * @param reduct The Reduct structure.
79 * @param function The function to compile into.
80 * @param enclosing The enclosing compiler context, or `REDUCT_NULL`.
81 */
83 reduct_compiler_t* enclosing);
84
85/**
86 * @brief Deinitialize a compiler context.
87 *
88 * @param compiler The compiler context to deinitialize.
89 */
91
92/**
93 * @brief Set a register as allocated.
94 *
95 * @param _compiler The compiler instance.
96 * @param _reg The register to set as allocated.
97 */
98#define REDUCT_REG_SET_ALLOCATED(_compiler, _reg) \
99 do \
100 { \
101 (_compiler)->regAlloc[(_reg) / 64] |= (1ULL << ((_reg) % 64)); \
102 if ((_reg) + 1 > (_compiler)->function->registerCount) \
103 { \
104 (_compiler)->function->registerCount = (_reg) + 1; \
105 } \
106 } while (0)
107
108/**
109 * @brief Clear a register's allocation status.
110 *
111 * @param _compiler The compiler instance.
112 * @param _reg The register to clear.
113 */
114#define REDUCT_REG_CLEAR_ALLOCATED(_compiler, _reg) ((_compiler)->regAlloc[(_reg) / 64] &= ~(1ULL << ((_reg) % 64)))
115
116/**
117 * @brief Check if a register is allocated.
118 *
119 * @param _compiler The compiler instance.
120 * @param _reg The register to check.
121 */
122#define REDUCT_REG_IS_ALLOCATED(_compiler, _reg) (((_compiler)->regAlloc[(_reg) / 64] & (1ULL << ((_reg) % 64))) != 0)
123
124/**
125 * @brief Set a register as a local.
126 *
127 * @param _compiler The compiler instance.
128 * @param _reg The register to set as a local.
129 */
130#define REDUCT_REG_SET_LOCAL(_compiler, _reg) ((_compiler)->regLocal[(_reg) / 64] |= (1ULL << ((_reg) % 64)))
131
132/**
133 * @brief Clear a register's local status.
134 *
135 * @param _compiler The compiler instance.
136 * @param _reg The register to clear.
137 */
138#define REDUCT_REG_CLEAR_LOCAL(_compiler, _reg) ((_compiler)->regLocal[(_reg) / 64] &= ~(1ULL << ((_reg) % 64)))
139
140/**
141 * @brief Check if a register is a local.
142 *
143 * @param _compiler The compiler instance.
144 * @param _reg The register to check.
145 */
146#define REDUCT_REG_IS_LOCAL(_compiler, _reg) (((_compiler)->regLocal[(_reg) / 64] & (1ULL << ((_reg) % 64))) != 0)
147
148/**
149 * @brief Allocate a new register.
150 *
151 * @param compiler The compiler context.
152 * @return The allocated register index.
153 */
155
156/**
157 * @brief Allocate a range of registers.
158 *
159 * @param compiler The compiler context.
160 * @param count The number of registers to allocate.
161 * @return The first register index in the allocated range.
162 */
164
165/**
166 * @brief Free a register.
167 *
168 * @param compiler The compiler context.
169 * @param reg The register index to free.
170 */
172
173/**
174 * @brief Free a range of registers.
175 *
176 * @param compiler The compiler context.
177 * @param start The first register index in the range to free.
178 * @param count The number of registers to free.
179 */
181
182/**
183 * @brief Create a `REDUCT_MODE_NONE` mode expression.
184 */
185#define REDUCT_EXPR_NONE() ((reduct_expr_t){.mode = REDUCT_MODE_NONE})
186
187/**
188 * @brief Create a `REDUCT_MODE_REG` mode expression.
189 *
190 * @param _reg The register index.
191 */
192#define REDUCT_EXPR_REG(_reg) ((reduct_expr_t){.mode = REDUCT_MODE_REG, .reg = (_reg)})
193
194/**
195 * @brief Create a `REDUCT_MODE_CONST` mode expression.
196 *
197 * @param _const The constant index.
198 */
199#define REDUCT_EXPR_CONST(_const) ((reduct_expr_t){.mode = REDUCT_MODE_CONST, .constant = (_const)})
200
201/**
202 * @brief Create a `REDUCT_MODE_CONST` mode expression for a specific item.
203 *
204 * @param _compiler The compiler context.
205 * @param _item The item to look up.
206 */
207#define REDUCT_EXPR_CONST_ITEM(_compiler, _item) \
208 REDUCT_EXPR_CONST(reduct_function_lookup_constant((_compiler)->reduct, (_compiler)->function, \
209 &(reduct_const_slot_t){.type = REDUCT_CONST_SLOT_ITEM, .item = (_item)}))
210
211/**
212 * @brief Create a `REDUCT_MODE_CONST` mode expression for a specific atom.
213 *
214 * @param _compiler The compiler context.
215 * @param _atom The atom to look up.
216 */
217#define REDUCT_EXPR_CONST_ATOM(_compiler, _atom) \
218 REDUCT_EXPR_CONST(reduct_function_lookup_constant((_compiler)->reduct, (_compiler)->function, \
219 &(reduct_const_slot_t){.type = REDUCT_CONST_SLOT_ITEM, \
220 .item = REDUCT_CONTAINER_OF(_atom, reduct_item_t, atom)}))
221
222/**
223 * @brief Create a `REDUCT_MODE_TARGET` mode expression.
224 *
225 * @param _reg The target register hint.
226 */
227#define REDUCT_EXPR_TARGET(_reg) ((reduct_expr_t){.mode = REDUCT_MODE_TARGET, .reg = (_reg)})
228
229/**
230 * @brief Create a `REDUCT_MODE_CONST` mode expression for the true constant.
231 *
232 * @param _compiler The compiler context.
233 */
234#define REDUCT_EXPR_TRUE(_compiler) \
235 REDUCT_EXPR_CONST(reduct_function_lookup_constant((_compiler)->reduct, (_compiler)->function, \
236 &(reduct_const_slot_t){.type = REDUCT_CONST_SLOT_ITEM, .item = (_compiler)->reduct->trueItem}))
237
238/**
239 * @brief Create a `REDUCT_MODE_CONST` mode expression for the false constant.
240 *
241 * @param _compiler The compiler context.
242 */
243#define REDUCT_EXPR_FALSE(_compiler) \
244 REDUCT_EXPR_CONST(reduct_function_lookup_constant((_compiler)->reduct, (_compiler)->function, \
245 &(reduct_const_slot_t){.type = REDUCT_CONST_SLOT_ITEM, .item = (_compiler)->reduct->falseItem}))
246
247/**
248 * @brief Create a `REDUCT_MODE_CONST` mode expression for the nil constant.
249 *
250 * @param _compiler The compiler context.
251 */
252#define REDUCT_EXPR_NIL(_compiler) \
253 REDUCT_EXPR_CONST(reduct_function_lookup_constant((_compiler)->reduct, (_compiler)->function, \
254 &(reduct_const_slot_t){.type = REDUCT_CONST_SLOT_ITEM, .item = (_compiler)->reduct->nilItem}))
255
256/**
257 * @brief Create a `REDUCT_MODE_CONST` mode expression for an integer.
258 *
259 * @param _compiler The compiler context.
260 * @param _val The integer value.
261 */
262#define REDUCT_EXPR_INT(_compiler, _val) \
263 REDUCT_EXPR_CONST_ATOM(_compiler, reduct_atom_lookup_int((_compiler)->reduct, (_val)))
264
265/**
266 * @brief Get the target register index from an expression, or -1 if no target is specified.
267 * @param _expr The expression to check.
268 */
269#define REDUCT_EXPR_GET_TARGET(_expr) (((_expr)->mode == REDUCT_MODE_TARGET) ? (_expr)->reg : REDUCT_REG_INVALID)
270
271/**
272 * @brief Create a `REDUCT_MODE_CONST` mode expression for a float.
273 *
274 * @param _compiler The compiler context.
275 * @param _val The float value.
276 */
277#define REDUCT_EXPR_FLOAT(_compiler, _val) \
278 REDUCT_EXPR_CONST_ATOM(_compiler, reduct_atom_lookup_float((_compiler)->reduct, (_val)))
279
280/**
281 * @brief Compiles a single Reduct item into an expression descriptor.
282 *
283 * @param compiler The compiler context.
284 * @param item The item to compile.
285 * @param Output pointer for the compiled expression.
286 */
288
289/**
290 * @brief Free resources associated with an expression descriptor.
291 *
292 * @param compiler The compiler context.
293 * @param expr The expression to free.
294 */
295static inline void reduct_expr_done(reduct_compiler_t* compiler, reduct_expr_t* expr)
296{
297 REDUCT_ASSERT(compiler != REDUCT_NULL);
298 REDUCT_ASSERT(expr != REDUCT_NULL);
299 if (expr->mode == REDUCT_MODE_REG)
300 {
301 reduct_reg_free(compiler, expr->reg);
302 }
303}
304
305/**
306 * @brief Allocate a new register, favoring the output expression's target if provided.
307 *
308 * @param compiler The compiler context.
309 * @param out The output expression which may contain a target hint.
310 * @return The allocated register index.
311 */
313{
314 REDUCT_ASSERT(compiler != REDUCT_NULL);
315 if (out != REDUCT_NULL && out->mode == REDUCT_MODE_TARGET)
316 {
317 return out->reg;
318 }
319 return reduct_reg_alloc(compiler);
320}
321
322/**
323 * @brief Get the first unallocated register index.
324 *
325 * @param compiler The compiler context.
326 * @return The first register index that is not currently allocated.
327 */
329{
330 for (reduct_int32_t i = REDUCT_REGISTER_MAX - 1; i >= 0; i--)
331 {
332 if (REDUCT_REG_IS_ALLOCATED(compiler, i))
333 {
334 return (reduct_reg_t)(i + 1);
335 }
336 }
337 return 0;
338}
339
340/**
341 * @brief Check if a local variable has finished being defined.
342 *
343 * If the local variable is not defined, then we are currently within the expression that defines it.
344 *
345 * @param _local The local variable descriptor.
346 */
347#define REDUCT_LOCAL_IS_DEFINED(_local) ((_local)->expr.mode != REDUCT_MODE_NONE)
348
349/**
350 * @brief Define a new local variable.
351 *
352 * @note The `reduct_local_def_done()` function must be called after this one.
353 *
354 * @param compiler The compiler context.
355 * @param name The name of the local.
356 * @return A pointer to the local variable descriptor.
357 */
359
360/**
361 * @brief Finalize a local variable definition with its value expression.
362 *
363 * @param compiler The compiler context.
364 * @param local The local variable descriptor.
365 * @param expr The expression representing the local's value.
366 */
368
369/**
370 * @brief Add a function argument local to the compiler context.
371 *
372 * @param compiler The compiler context.
373 * @param name The name of the argument.
374 * @return A pointer to the local variable descriptor.
375 */
377
378/**
379 * @brief Pop local variables from the stack, releasing their registers if they are no longer used.
380 *
381 * @param compiler The compiler context.
382 * @param toCount The local count to restore to.
383 * @param result The result expression of the block, whose register should not be freed.
384 */
386
387/**
388 * @brief Look up a local by name and return its expression.
389 *
390 * @param compiler The compiler context.
391 * @param name The name of the local.
392 * @return A pointer to the local variable descriptor, or `REDUCT_NULL` if not found.
393 */
395
396/**
397 * @brief Emits an instruction to the current function.
398 *
399 * @param compiler The compiler context.
400 * @param inst The instruction to emit.
401 */
402static inline void reduct_compile_inst(reduct_compiler_t* compiler, reduct_inst_t inst)
403{
404 REDUCT_ASSERT(compiler != REDUCT_NULL);
405 reduct_uint32_t pos = compiler->lastItem != REDUCT_NULL ? compiler->lastItem->position : 0;
406 reduct_function_emit(compiler->reduct, compiler->function, inst, pos);
407}
408
409/**
410 * @brief Emits a `REDUCT_OPCODE_LIST` instruction, that creates a list in the target register.
411 *
412 * @param compiler The compiler context.
413 * @param target The target register.
414 */
415static inline void reduct_compile_list(reduct_compiler_t* compiler, reduct_reg_t target)
416{
417 REDUCT_ASSERT(compiler != REDUCT_NULL);
419}
420
421/**
422 * @brief Emits a `REDUCT_OPCODE_CALL` instruction, that returns its result in the target register.
423 *
424 * @param compiler The compiler context.
425 * @param target The target register.
426 * @param callable The callable expression.
427 * @param arity The number of arguments.
428 */
429static inline void reduct_compile_call(reduct_compiler_t* compiler, reduct_reg_t target, reduct_expr_t* callable,
430 reduct_uint32_t arity)
431{
432 REDUCT_ASSERT(compiler != REDUCT_NULL);
433 REDUCT_ASSERT(callable != REDUCT_NULL);
434 REDUCT_ASSERT(callable->mode == REDUCT_MODE_REG || callable->mode == REDUCT_MODE_CONST);
435 reduct_compile_inst(compiler,
436 REDUCT_INST_MAKE_ABC((reduct_opcode_t)(REDUCT_OPCODE_CALL | callable->mode), target, arity, callable->value));
437}
438
439/**
440 * @brief Emits a `REDUCT_OPCODE_MOVE` instruction, that moves the value of the source expression to the target
441 * register.
442 *
443 * @param compiler The compiler context.
444 * @param target The target register.
445 * @param expr The source expression.
446 */
447static inline void reduct_compile_move(reduct_compiler_t* compiler, reduct_reg_t target, reduct_expr_t* expr)
448{
449 REDUCT_ASSERT(compiler != REDUCT_NULL);
450 REDUCT_ASSERT(expr != REDUCT_NULL);
454
455 reduct_compile_inst(compiler,
457}
458
459/**
460 * @brief Emits a jump instruction without a target offset.
461 *
462 * @param compiler The compiler context.
463 * @param op The jump opcode (e.g., `REDUCT_OPCODE_JMP`, `REDUCT_OPCODE_JMPT`, `REDUCT_OPCODE_JMPF`).
464 * @param a The register to test (if not `REDUCT_OPCODE_JMP`).
465 * @return The index of the emitted instruction to be patched later.
466 */
468{
469 REDUCT_ASSERT(compiler != REDUCT_NULL);
470 reduct_size_t pos = compiler->function->instCount;
471 reduct_compile_inst(compiler, REDUCT_INST_MAKE_ASBX(op, a, 0));
472 return pos;
473}
474
475/**
476 * @brief Patch a previously emitted jump instruction to point to the current instruction.
477 *
478 * @param compiler The compiler context.
479 * @param pos The index of the jump instruction to patch.
480 */
482{
483 REDUCT_ASSERT(compiler != REDUCT_NULL);
484 reduct_int64_t offset = (reduct_int64_t)(compiler->function->instCount - pos - 1);
485 compiler->function->insts[pos] = REDUCT_INST_SET_SBX(compiler->function->insts[pos], offset);
486}
487
488/**
489 * @brief Patch a list of jump instructions to point to the current instruction.
490 *
491 * @param compiler The compiler context.
492 * @param jumps Array of jump instruction indices.
493 * @param count Number of jumps in the array.
494 */
496 reduct_size_t count)
497{
498 for (reduct_size_t i = 0; i < count; i++)
499 {
500 reduct_compile_jump_patch(compiler, jumps[i]);
501 }
502}
503
504/**
505 * @brief Emits a move instruction or allocates a new register if the expression is not already in a register.
506 *
507 * @param compiler The compiler context.
508 * @param expr The expression to move or allocate.
509 * @return The register where the value is stored.
510 */
512{
513 REDUCT_ASSERT(compiler != REDUCT_NULL);
514 REDUCT_ASSERT(expr != REDUCT_NULL);
516 if (expr->mode == REDUCT_MODE_REG)
517 {
518 return expr->reg;
519 }
520
521 reduct_reg_t target = reduct_reg_alloc(compiler);
522 reduct_compile_move(compiler, target, expr);
523 *expr = REDUCT_EXPR_REG(target);
524 return target;
525}
526
527/**
528 * @brief Emits a `REDUCT_OPCODE_RET` instruction.
529 *
530 * @param compiler The compiler context.
531 * @param expr The expression to return.
532 */
533static inline void reduct_compile_return(reduct_compiler_t* compiler, reduct_expr_t* expr)
534{
535 REDUCT_ASSERT(compiler != REDUCT_NULL);
536 REDUCT_ASSERT(expr != REDUCT_NULL);
537
538 if (expr->mode == REDUCT_MODE_REG)
539 {
540 reduct_reg_t retReg = expr->reg;
541 reduct_uint32_t retInstPos = compiler->function->instCount;
542
543 for (reduct_size_t i = 0; i < retInstPos; i++)
544 {
545 reduct_inst_t inst = compiler->function->insts[i];
547
548 if (op != REDUCT_OPCODE_CALL)
549 {
550 continue;
551 }
552
554
555 reduct_size_t curr = i + 1;
556 reduct_reg_t currentReg = REDUCT_INST_GET_A(inst);
558
559 while (curr < retInstPos)
560 {
561 reduct_inst_t nextInst = compiler->function->insts[curr];
562 reduct_opcode_t nextOp = REDUCT_INST_GET_OP(nextInst);
563 reduct_opcode_t nextOpBase = REDUCT_INST_GET_OP_BASE(nextInst);
564
565 if (nextOp == REDUCT_OPCODE_MOV && REDUCT_INST_GET_A(nextInst) == retReg &&
566 REDUCT_INST_GET_C(nextInst) == currentReg)
567 {
568 currentReg = retReg;
569 curr++;
570 }
571 else if (nextOpBase == REDUCT_OPCODE_JMP)
572 {
573 reduct_int32_t offset = REDUCT_INST_GET_SBX(nextInst);
574 if (offset < 0)
575 {
576 valid = REDUCT_FALSE;
577 break;
578 }
579 curr = curr + 1 + offset;
580 }
581 else
582 {
583 valid = REDUCT_FALSE;
584 break;
585 }
586 }
587
588 if (valid && currentReg == retReg && curr == retInstPos)
589 {
590 isTail = REDUCT_TRUE;
591 }
592
593 if (isTail)
594 {
596 compiler->function->insts[i] =
597 (inst & ~REDUCT_INST_MASK_OPCODE) | ((REDUCT_OPCODE_TAILCALL | mode) & REDUCT_INST_MASK_OPCODE);
598 }
599 }
600 }
601
602 if (expr->mode == REDUCT_MODE_NONE)
603 {
604 reduct_expr_t nilExpr = REDUCT_EXPR_NIL(compiler);
605 reduct_uint32_t pos = compiler->lastItem != REDUCT_NULL ? compiler->lastItem->position : 0;
606 reduct_function_emit(compiler->reduct, compiler->function,
608 return;
609 }
610
612 reduct_compile_inst(compiler,
614}
615
616/**
617 * @brief Emits an `REDUCT_OPCODE_APPEND` instruction.
618 *
619 * @param compiler The compiler context.
620 * @param target The target list register.
621 * @param expr The expression to append.
622 */
623static inline void reduct_compile_append(reduct_compiler_t* compiler, reduct_reg_t target, reduct_expr_t* expr)
624{
625 REDUCT_ASSERT(compiler != REDUCT_NULL);
626 REDUCT_ASSERT(expr != REDUCT_NULL);
628 reduct_compile_inst(compiler,
630}
631
632/**
633 * @brief Emits a comparison, arithmetic or bitwise instruction.
634 *
635 * @param compiler The compiler context.
636 * @param opBase The base opcode (without a mode) for the operation (e.g, `REDUCT_OPCODE_ADD`, `REDUCT_OPCODE_EQ`).
637 * @param target The target register.
638 * @param left The left operand register.
639 * @param right The right operand expression.
640 */
641static inline void reduct_compile_binary(reduct_compiler_t* compiler, reduct_opcode_t opBase, reduct_reg_t target,
642 reduct_reg_t left, reduct_expr_t* right)
643{
644 REDUCT_ASSERT(compiler != REDUCT_NULL);
645 REDUCT_ASSERT(right != REDUCT_NULL);
647 reduct_compile_inst(compiler,
648 REDUCT_INST_MAKE_ABC((reduct_opcode_t)(opBase | right->mode), target, left, right->value));
649}
650
651/**
652 * @brief Emits a `REDUCT_OPCODE_CLOSURE` instruction.
653 *
654 * @param compiler The compiler context.
655 * @param target The target register.
656 * @param funcConst The constant index of the function prototype.
657 */
658static inline void reduct_compile_closure(reduct_compiler_t* compiler, reduct_reg_t target, reduct_const_t funcConst)
659{
660 REDUCT_ASSERT(compiler != REDUCT_NULL);
661 reduct_compile_inst(compiler, REDUCT_INST_MAKE_ABC(REDUCT_OPCODE_CLOSURE, target, 0, funcConst));
662}
663
664/**
665 * @brief Emits a `REDUCT_OPCODE_CAPTURE` instruction.
666 *
667 * @param compiler The compiler context.
668 * @param closureReg The register containing the closure.
669 * @param slot The constant slot index in the closure to capture into.
670 * @param expr The expression to be captured.
671 */
672static inline void reduct_compile_capture(reduct_compiler_t* compiler, reduct_reg_t closureReg, reduct_uint32_t slot,
673 reduct_expr_t* expr)
674{
675 REDUCT_ASSERT(compiler != REDUCT_NULL);
676 REDUCT_ASSERT(expr != REDUCT_NULL);
678 reduct_compile_inst(compiler,
680}
681
682#endif
Core definitions and structures.
size_t reduct_size_t
Definition defs.h:100
reduct_bool_t
Boolean type.
Definition defs.h:135
@ REDUCT_FALSE
Definition defs.h:137
@ REDUCT_TRUE
Definition defs.h:136
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
#define REDUCT_ASSERT(_cond)
Definition defs.h:25
int32_t reduct_int32_t
Definition defs.h:94
#define REDUCT_API
Definition defs.h:7
uint16_t reduct_uint16_t
Definition defs.h:97
uint64_t reduct_uint64_t
Definition defs.h:93
#define REDUCT_NULL
Definition defs.h:23
Compiled function.
Garbage collection.
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
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_function_t * reduct_compile(reduct_t *reduct, reduct_handle_t *ast)
Compiles a Reduct AST into a callable bytecode function.
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.
static reduct_reg_t reduct_reg_get_base(reduct_compiler_t *compiler)
Get the first unallocated register index.
Definition compile.h:328
static void reduct_compile_inst(reduct_compiler_t *compiler, reduct_inst_t inst)
Emits an instruction to the current function.
Definition compile.h:402
struct reduct_compiler * enclosing
The enclosing compiler context, or REDUCT_NULL.
Definition compile.h:53
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
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_atom_t * name
The name of the local variable.
Definition compile.h:43
reduct_t * reduct
The Reduct structure.
Definition compile.h:54
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
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
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
reduct_item_t * lastItem
The last item processed by the compiler, used for error reporting.
Definition compile.h:60
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
#define REDUCT_REG_IS_ALLOCATED(_compiler, _reg)
Check if a register is allocated.
Definition compile.h:122
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.
reduct_uint16_t reduct_const_t
Constant index type.
Definition function.h:71
static void reduct_function_emit(struct reduct *reduct, reduct_function_t *func, reduct_inst_t inst, reduct_uint32_t position)
Emit an instruction to the function.
Definition function.h:128
#define REDUCT_INST_GET_C(_inst)
Get the C operand from an instruction.
Definition inst.h:185
#define REDUCT_INST_MAKE_ASBX(_op, _a, _sbx)
Create an instruction with opcode and A operands, and SBx B operand.
Definition inst.h:146
reduct_mode_t
Opcode mode enumeration.
Definition inst.h:37
#define REDUCT_INST_GET_A(_inst)
Get the A operand from an instruction.
Definition inst.h:171
#define REDUCT_INST_SET_SBX(_inst, _sbx)
Set the SBX operand in an instruction.
Definition inst.h:211
#define REDUCT_INST_GET_SBX(_inst)
Get the SBX operand from an instruction.
Definition inst.h:192
#define REDUCT_INST_MAKE_ABC(_op, _a, _b, _c)
Create an instruction with opcode, A, B, and C operands.
Definition inst.h:133
#define REDUCT_INST_GET_OP(_inst)
Get the opcode from an instruction.
Definition inst.h:156
reduct_opcode_t
Opcode enumeration.
Definition inst.h:49
reduct_uint32_t reduct_inst_t
Instruction type.
Definition inst.h:97
#define REDUCT_INST_MASK_OPCODE
Opcode mask.
Definition inst.h:119
#define REDUCT_INST_GET_OP_BASE(_inst)
Get the opcode base (without reduct_mode_t) from an instruction. Mask clears the REDUCT_MODE_CONST bi...
Definition inst.h:163
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_MODE_TARGET
Compilation target hint mode.
Definition inst.h:39
@ 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_MOV
(A, C) Move value in R/K(C) to R(A).
Definition inst.h:57
@ REDUCT_OPCODE_RET
(C) Return value in R/K(C).
Definition inst.h:58
@ 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_JMP
(sBx) Unconditional jump by relative offset sBx.
Definition inst.h:52
@ 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_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_CAPTURE
(A, B, C) Capture R/K(C) into constant slot B in closure R(A).
Definition inst.h:80
Bytecode instruction format.
Item management.
List management.
Atom structure.
Definition atom.h:48
Compiler structure.
Definition compile.h:52
Expression descriptor structure.
Definition compile.h:28
Compiled function structure.
Definition function.h:78
reduct_inst_t * insts
An array of instructions.
Definition function.h:81
reduct_uint32_t instCount
Number of instructions.
Definition function.h:79
Item structure.
Definition item.h:57
reduct_uint32_t position
The position in the input buffer where the item was parsed.
Definition item.h:59
Local structure.
Definition compile.h:42
State structure.
Definition core.h:61