Implement loops #4

Merged
samsonium merged 24 commits from feat-loops into v1.1 2026-10-25 02:01:47 +00:00
3 changed files with 202 additions and 27 deletions
Showing only changes of commit a20743a835 - Show all commits
+196 -24
View File
@@ -6,42 +6,214 @@
#include <compiler/utils/fzl_symtable.h> #include <compiler/utils/fzl_symtable.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <string.h>
ssize_t check_top;
fzl_nodetype_t check_tree[256];
void ghost_walk_changed(fzl_node_t *node, bool *changed, fzl_sym_t *sym)
Outdated
Review

Add comment

Add comment
{
if (!node || !changed || *changed)
return;
check_tree[check_top++] = node->type;
switch (node->type)
{
case FZL_NODETYPE_DECLARATION:
case FZL_NODETYPE_CONSTRUCT:
case FZL_NODETYPE_CLASS:
case FZL_NODETYPE_FUNCTION:
case FZL_NODETYPE_LITERAL:
break;
case FZL_NODETYPE_UNARY_PLUS:
case FZL_NODETYPE_UNARY_MINUS:
case FZL_NODETYPE_NOT:
ghost_walk_changed(node->unary_op.operand, changed, sym);
break;
case FZL_NODETYPE_ADD:
case FZL_NODETYPE_SUB:
case FZL_NODETYPE_MUL:
case FZL_NODETYPE_DIV:
case FZL_NODETYPE_POW:
case FZL_NODETYPE_MOD:
case FZL_NODETYPE_OR:
case FZL_NODETYPE_AND:
case FZL_NODETYPE_EQUAL:
case FZL_NODETYPE_NEQUAL:
case FZL_NODETYPE_LESS:
case FZL_NODETYPE_LESS_EQUAL:
case FZL_NODETYPE_GREATER:
case FZL_NODETYPE_GREATER_EQUAL:
case FZL_NODETYPE_ASSIGN:
ghost_walk_changed(node->binary_op.left, changed, sym);
ghost_walk_changed(node->binary_op.right, changed, sym);
break;
case FZL_NODETYPE_FIELD:
ghost_walk_changed(node->memb.parent, changed, sym);
ghost_walk_changed(node->memb.field, changed, sym);
break;
case FZL_NODETYPE_RETURN:
ghost_walk_changed(node->ret.value, changed, sym);
break;
case FZL_NODETYPE_CONDITIONAL:
ghost_walk_changed(node->cond.condition, changed, sym);
ghost_walk_changed(node->cond.true_block, changed, sym);
ghost_walk_changed(node->cond.else_block, changed, sym);
break;
case FZL_NODETYPE_LOOP:
ghost_walk_changed(node->loop.cond, changed, sym);
ghost_walk_changed(node->loop.step, changed, sym);
ghost_walk_changed(node->loop.body, changed, sym);
break;
case FZL_NODETYPE_BLOCK:
for (size_t i = 0; i < node->list.entry_count; i++)
ghost_walk_changed(node->list.entries[i], changed, sym);
break;
case FZL_NODETYPE_CALL:
ghost_walk_changed(node->call.callee, changed, sym);
for (size_t i = 0; i < node->call.args_count; i++)
ghost_walk_changed(node->call.args[i], changed, sym);
break;
case FZL_NODETYPE_IDENTIFIER:
if (strcmp(node->token->value, sym->name) == 0)
{
*changed = true;
}
if (*changed)
{
*changed = false;
for (ssize_t i = check_top - 1; i >= 0; i--)
{
fzl_nodetype_t cur_t = check_tree[i];
if (cur_t == FZL_NODETYPE_ADD || cur_t == FZL_NODETYPE_SUB ||
cur_t == FZL_NODETYPE_MUL || cur_t == FZL_NODETYPE_DIV ||
cur_t == FZL_NODETYPE_POW || cur_t == FZL_NODETYPE_MOD ||
cur_t == FZL_NODETYPE_UNARY_MINUS)
{
*changed = true;
break;
}
}
}
break;
}
check_tree[--check_top] = 0;
}
// Whether value changed in loop body
bool value_is_changed(fzl_node_t *node, fzl_sym_t *sym)
{
if (!node || !sym)
return false;
bool changed = false;
check_top = 0;
memset(check_tree, 0, sizeof(check_tree));
ghost_walk_changed(node, &changed, sym);
return changed;
}
// Try to find symbol in loop condition node
bool retrieve_cond_sym(fzl_walker_t *walker, fzl_node_t *node, fzl_sym_t *sym)
{
if (!walker || !node)
return false;
switch (node->type)
{
case FZL_NODETYPE_BLOCK:
case FZL_NODETYPE_CALL:
case FZL_NODETYPE_LITERAL:
case FZL_NODETYPE_CONDITIONAL:
case FZL_NODETYPE_FUNCTION:
case FZL_NODETYPE_RETURN:
case FZL_NODETYPE_CLASS:
case FZL_NODETYPE_FIELD:
case FZL_NODETYPE_CONSTRUCT:
case FZL_NODETYPE_LOOP:
case FZL_NODETYPE_ASSIGN:
case FZL_NODETYPE_DECLARATION:
return false;
case FZL_NODETYPE_UNARY_MINUS:
case FZL_NODETYPE_UNARY_PLUS:
case FZL_NODETYPE_NOT:
return retrieve_cond_sym(walker, node->unary_op.operand, sym);
case FZL_NODETYPE_ADD:
case FZL_NODETYPE_SUB:
case FZL_NODETYPE_MUL:
case FZL_NODETYPE_DIV:
case FZL_NODETYPE_POW:
case FZL_NODETYPE_MOD:
case FZL_NODETYPE_AND:
case FZL_NODETYPE_OR:
case FZL_NODETYPE_LESS:
case FZL_NODETYPE_LESS_EQUAL:
case FZL_NODETYPE_GREATER:
case FZL_NODETYPE_GREATER_EQUAL:
case FZL_NODETYPE_EQUAL:
case FZL_NODETYPE_NEQUAL:
if (retrieve_cond_sym(walker, node->binary_op.left, sym))
return true;
if (retrieve_cond_sym(walker, node->binary_op.right, sym))
return true;
return false;
case FZL_NODETYPE_IDENTIFIER:
{
bool exists;
for (ssize_t i = walker->sym_top - 1; i >= 0; i--)
{
if ((exists = fzl_symt_get(walker->syms[i], (char *)node->token->value,
sym)))
break;
}
return exists;
}
}
return false;
}
// Check for infinite loop // Check for infinite loop
bool is_infinite_loop(fzl_walker_t *walker, size_t start_ip, size_t end_ip) bool is_infinite_loop(fzl_walker_t *walker, fzl_node_t *node, size_t start_ip,
size_t end_ip)
{ {
if (!walker) if (!walker)
return false; return false;
end_ip = (end_ip >= walker->op_count) ? (walker->op_count - 1) : end_ip; end_ip = (end_ip >= walker->op_count) ? (walker->op_count - 1) : end_ip;
// Can we determine an init block?
size_t maybe_init_start = start_ip + 1;
size_t maybe_init_end = start_ip + 6;
fzl_const_t *declared = NULL;
for (size_t i = maybe_init_start; i <= maybe_init_end; i++)
{
if (walker->ops[i] != FZL_OPCODE_STORE)
continue;
declared = &walker->consts->array[walker->ops[i - 1]];
break;
}
if (declared)
{
fzl_sym_t sym; fzl_sym_t sym;
bool found = false; bool sym_exists = retrieve_cond_sym(walker, node->loop.cond, &sym);
for (ssize_t i = walker->sym_top - 1; i >= 0; i--) if (sym_exists)
if ((found = fzl_symt_get(walker->syms[i], {
(char *)declared->as.string.chars, &sym))) // fzl_sym_t sym;
break; // bool found = false;
// for (ssize_t i = walker->sym_top - 1; i >= 0; i--)
if (!found) // if ((found = fzl_symt_get(walker->syms[i],
return false; // suspicious // (char *)declared->as.string.chars, &sym)))
// break;
if (sym.type >= FZL_TYPE_INT8) if (sym.type >= FZL_TYPE_INT8)
{ {
bool value_changed = value_is_changed(node, &sym);
if (value_changed)
return false;
} }
} }
+5 -2
View File
@@ -14,7 +14,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
extern bool is_infinite_loop(fzl_walker_t *walker, size_t ls, size_t le); extern bool is_infinite_loop(fzl_walker_t *walker, fzl_node_t *node, size_t ls,
size_t le);
char *null_name = "<null>"; char *null_name = "<null>";
char wlast_err[256]; char wlast_err[256];
@@ -221,6 +222,7 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
push_op(walker, FZL_OPCODE_MK_ENVTABLE); push_op(walker, FZL_OPCODE_MK_ENVTABLE);
walker->syms[walker->sym_top++] = fzl_mksymt(); walker->syms[walker->sym_top++] = fzl_mksymt();
size_t loop_begin_ip = walker->op_count;
if (node->loop.init) if (node->loop.init)
{ {
@@ -274,9 +276,10 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
push_op(walker, FZL_OPCODE_RM_ENVTABLE); push_op(walker, FZL_OPCODE_RM_ENVTABLE);
bool is_infinite = bool is_infinite =
is_infinite_loop(walker, start_ip, walker->op_count - 2); is_infinite_loop(walker, node, loop_begin_ip, walker->op_count - 2);
if (is_infinite) if (is_infinite)
{ {
free(newctx->breaks);
snprintf(wlast_err, sizeof(wlast_err), snprintf(wlast_err, sizeof(wlast_err),
"'%s': infinite loop detected at %ld:%ld", "'%s': infinite loop detected at %ld:%ld",
node->token->filename, node->token->ln, node->token->cn); node->token->filename, node->token->ln, node->token->cn);
1
+1 -1
View File
@@ -1,3 +1,3 @@
for (int i = 0; i < 5; i = i - 1) for (int i = 0; i < 5; i = i + 0)
{} {}