90 lines
2.6 KiB
C
90 lines
2.6 KiB
C
#include <common/fzl_types.h>
|
|
#include <compiler/fzl_analyzer.h>
|
|
#include <compiler/fzl_parser.h>
|
|
#include <compiler/fzl_token.h>
|
|
#include <compiler/internals/analyzer.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
|
|
// Analyze block
|
|
fzl_an_res_t analyze_block(fzl_analyzer_t *analyzer, fzl_node_t *block_node)
|
|
{
|
|
if (!analyzer)
|
|
return (fzl_an_res_t){.error = true};
|
|
|
|
if (!block_node || block_node->type != FZL_NODETYPE_BLOCK)
|
|
{
|
|
snprintf(an_problem, sizeof(an_problem), "node is not a block");
|
|
an_push_error(analyzer, NULL, an_problem);
|
|
return (fzl_an_res_t){.error = true};
|
|
}
|
|
|
|
an_nest_ctx(analyzer, FZL_AN_CTX_TYPE_UNNECESSARY);
|
|
|
|
bool has_return = false;
|
|
bool error = false;
|
|
for (size_t i = 0; i < block_node->list.entry_count; i++)
|
|
{
|
|
if (has_return)
|
|
an_push_warning(analyzer, block_node->list.entries[i]->token,
|
|
"this statement will never execute");
|
|
|
|
fzl_an_res_t entry_res =
|
|
analyze_common(analyzer, block_node->list.entries[i]);
|
|
if (entry_res.error)
|
|
error = true;
|
|
|
|
if (block_node->list.entries[i]->type == FZL_NODETYPE_RETURN)
|
|
has_return = true;
|
|
}
|
|
|
|
fzl_an_ctx_t *fnctx = analyzer->ctx;
|
|
while (fnctx != NULL)
|
|
{
|
|
if (fnctx && fnctx->type == FZL_AN_CTX_TYPE_FUNCTION)
|
|
break;
|
|
|
|
fnctx = fnctx->parent;
|
|
}
|
|
|
|
if (fnctx && fnctx->type == FZL_AN_CTX_TYPE_FUNCTION)
|
|
{
|
|
fzl_type_t rettype = an_toktotype(fnctx->fn->fn.type);
|
|
char *classname = NULL;
|
|
char *rettype_str = an_typetostr(rettype, classname);
|
|
|
|
if (rettype == FZL_TYPE_OBJECT)
|
|
classname = (char *)fnctx->fn->fn.type->value;
|
|
|
|
if (rettype != FZL_TYPE_NULL)
|
|
{
|
|
if (!has_return || block_node->list.entry_count < 1)
|
|
{
|
|
snprintf(an_problem, sizeof(an_problem),
|
|
"'return <%s>' is expected in the function with non-null "
|
|
"return type",
|
|
rettype_str);
|
|
an_push_error(analyzer, block_node->token, an_problem);
|
|
return (fzl_an_res_t){.error = true};
|
|
}
|
|
|
|
fzl_node_t *last_node =
|
|
block_node->list.entries[block_node->list.entry_count - 1];
|
|
if (last_node->type != FZL_NODETYPE_RETURN)
|
|
{
|
|
// NOTE: replace with ghost walker to check if all branch return an
|
|
// expected value type
|
|
snprintf(an_problem, sizeof(an_problem),
|
|
"expected last statement in block to be 'return <%s>'",
|
|
rettype_str);
|
|
an_push_error(analyzer, last_node->token, an_problem);
|
|
return (fzl_an_res_t){.error = true};
|
|
}
|
|
}
|
|
}
|
|
|
|
an_fin_ctx(analyzer);
|
|
|
|
return (fzl_an_res_t){.error = error, .type = FZL_TYPE_NULL};
|
|
}
|