feat: implement loops

This commit is contained in:
samsonium
2026-10-22 18:24:28 +03:00
parent 0188991f4d
commit cc5bbd61f2
7 changed files with 396 additions and 4 deletions
+101 -1
View File
@@ -200,6 +200,96 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
{
switch (node->type)
{
// NOTE: add new levels for infinite loop check:
// 1. Dead condition (f.e. `while (i < 5)` w/o `i` increment)
// 2. Step direction (f.e. `for (; i > 5; i = i - 1)`)
case FZL_NODETYPE_LOOP:
{
fzl_walk_ctx_t *newctx = nest_ctx(walker, FZL_WALK_CTX_TYPE_LOOP);
if (!newctx)
{
snprintf(wlast_err, sizeof(wlast_err), "failed to nest context");
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
}
newctx->initial_env_lvl = walker->sym_top - 1;
newctx->breaks_count = 0;
newctx->breaks_remainder = 2;
newctx->breaks = malloc(newctx->breaks_remainder * sizeof(size_t));
push_op(walker, FZL_OPCODE_MK_ENVTABLE);
walker->syms[walker->sym_top++] = fzl_mksymt();
if (node->loop.init)
{
fzl_walk_res_t res = walk(walker, node->loop.init);
if (res.error)
{
free(newctx->breaks);
return res;
}
}
size_t start_ip = walker->op_count;
if (node->loop.cond)
{
fzl_walk_res_t res = walk(walker, node->loop.cond);
if (res.error)
{
free(newctx->breaks);
return res;
}
}
else
{
push_op(walker, FZL_OPCODE_PUSHNUM);
push_word(walker, 1);
}
push_op(walker, FZL_OPCODE_JZ);
newctx->breaks[newctx->breaks_count++] = walker->op_count;
push_word(walker, 0);
fzl_walk_res_t loop_body_res = walk(walker, node->loop.body);
if (loop_body_res.error)
{
free(newctx->breaks);
return loop_body_res;
}
if (node->loop.step)
{
fzl_walk_res_t res = walk(walker, node->loop.step);
if (res.error)
{
free(newctx->breaks);
return res;
}
}
push_op(walker, FZL_OPCODE_JMP);
push_word(walker, start_ip);
push_op(walker, FZL_OPCODE_RM_ENVTABLE);
for (size_t i = walker->sym_top - 1; i > newctx->initial_env_lvl; i--)
fzl_freesymt(walker->syms[--walker->sym_top]);
// backpatch `break`s
for (size_t i = 0; i < newctx->breaks_count; i++)
walker->ops[newctx->breaks[i]] = walker->op_count - 1;
free(newctx->breaks);
if (!fin_ctx(walker))
{
snprintf(wlast_err, sizeof(wlast_err),
"failed to finish loop context");
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
}
current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false};
break;
}
case FZL_NODETYPE_CLASS:
{
fzl_walk_ctx_t *newctx = nest_ctx(walker, FZL_WALK_CTX_TYPE_CLASS);
@@ -461,7 +551,16 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
case FZL_NODETYPE_RETURN:
{
if (!walker->ctx || walker->ctx->type != FZL_WALK_CTX_TYPE_FN)
fzl_walk_ctx_t *ctx = walker->ctx;
while (ctx)
{
if (ctx && ctx->type == FZL_WALK_CTX_TYPE_FN)
break;
ctx = ctx->parent;
}
if (!ctx || ctx->type != FZL_WALK_CTX_TYPE_FN)
{
snprintf(
wlast_err, sizeof(wlast_err),
@@ -731,6 +830,7 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
}
fzl_freesymt(walker->syms[--walker->sym_top]);
push_op(walker, FZL_OPCODE_RM_ENVTABLE);
current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false};
break;
case FZL_NODETYPE_CALL: