64 lines
1.4 KiB
C
64 lines
1.4 KiB
C
#include <common/fzl_types.h>
|
|
#include <compiler/fzl_gen.h>
|
|
#include <compiler/internals/gen.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
|
|
// While or for loops
|
|
gen_res_t gen_loop(fzl_gen_t *gen, fzl_node_t *node)
|
|
{
|
|
if (!gen || !node)
|
|
return gen_error;
|
|
|
|
fzl_gen_ctx_t *ctx = gen_ctx(gen, FZL_GEN_CTX_TYPE_LOOP, node);
|
|
if (!ctx)
|
|
return gen_error;
|
|
|
|
gen_op(gen, FZL_OPCODE_MK_ENVTABLE);
|
|
|
|
if (node->loop.init)
|
|
if (gen_common(gen, node->loop.init).error)
|
|
return gen_error;
|
|
|
|
size_t start_ip = gen->ops_count;
|
|
if (node->loop.cond)
|
|
{
|
|
if (gen_common(gen, node->loop.cond).error)
|
|
return gen_error;
|
|
}
|
|
else
|
|
{
|
|
gen_op(gen, FZL_OPCODE_PUSHNUM);
|
|
gen_word(gen, 1);
|
|
}
|
|
|
|
gen_op(gen, FZL_OPCODE_JZ);
|
|
ctx->loop.breaks[ctx->loop.breaks_count++] = gen->ops_count;
|
|
gen_word(gen, 0);
|
|
|
|
if (gen_common(gen, node->loop.body).error)
|
|
return gen_error;
|
|
|
|
if (node->loop.step)
|
|
if (gen_common(gen, node->loop.step).error)
|
|
return gen_error;
|
|
|
|
gen_op(gen, FZL_OPCODE_JMP);
|
|
gen_word(gen, start_ip);
|
|
|
|
// backpatch `break`s
|
|
for (size_t i = 0; i < ctx->loop.breaks_count; i++)
|
|
gen->ops[ctx->loop.breaks[i]] = gen->ops_count;
|
|
|
|
gen_op(gen, FZL_OPCODE_RM_ENVTABLE);
|
|
|
|
for (size_t i = gen->syms_top - 1; i > ctx->level; i--)
|
|
fzl_freesymt(gen->syms[--gen->syms_top]);
|
|
|
|
ctx = gen_fin_ctx(gen);
|
|
if (!ctx)
|
|
return gen_error;
|
|
|
|
return gen_ok_null;
|
|
}
|