|
|
|
@@ -6,42 +6,214 @@
|
|
|
|
|
#include <compiler/utils/fzl_symtable.h>
|
|
|
|
|
#include <stdbool.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)
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
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)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
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++)
|
|
|
|
|
fzl_sym_t sym;
|
|
|
|
|
bool sym_exists = retrieve_cond_sym(walker, node->loop.cond, &sym);
|
|
|
|
|
if (sym_exists)
|
|
|
|
|
{
|
|
|
|
|
if (walker->ops[i] != FZL_OPCODE_STORE)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
declared = &walker->consts->array[walker->ops[i - 1]];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (declared)
|
|
|
|
|
{
|
|
|
|
|
fzl_sym_t sym;
|
|
|
|
|
bool found = false;
|
|
|
|
|
for (ssize_t i = walker->sym_top - 1; i >= 0; i--)
|
|
|
|
|
if ((found = fzl_symt_get(walker->syms[i],
|
|
|
|
|
(char *)declared->as.string.chars, &sym)))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
return false; // suspicious
|
|
|
|
|
// fzl_sym_t sym;
|
|
|
|
|
// bool found = false;
|
|
|
|
|
// for (ssize_t i = walker->sym_top - 1; i >= 0; i--)
|
|
|
|
|
// if ((found = fzl_symt_get(walker->syms[i],
|
|
|
|
|
// (char *)declared->as.string.chars, &sym)))
|
|
|
|
|
// break;
|
|
|
|
|
|
|
|
|
|
if (sym.type >= FZL_TYPE_INT8)
|
|
|
|
|
{
|
|
|
|
|
bool value_changed = value_is_changed(node, &sym);
|
|
|
|
|
if (value_changed)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Add comment