Impl analyzer #5

Merged
samsonium merged 11 commits from impl-analyzer into v1.1 2026-10-27 12:43:08 +00:00
4 changed files with 127 additions and 0 deletions
Showing only changes of commit d7630dbb6a - Show all commits
+6
View File
@@ -31,6 +31,11 @@ typedef struct fzl_an_ctx
struct fzl_an_ctx *parent;
fzl_an_ctx_type_t type;
union
{
fzl_node_t *fn;
};
} fzl_an_ctx_t;
// Analyzer descriptor
@@ -73,6 +78,7 @@ fzl_an_res_t analyze_identifier(fzl_analyzer_t *analyzer, fzl_node_t *id);
fzl_an_res_t analyze_conditional(fzl_analyzer_t *analyzer, fzl_node_t *cond);
fzl_an_res_t analyze_function(fzl_analyzer_t *analyzer, fzl_node_t *fn_node);
fzl_an_res_t analyze_block(fzl_analyzer_t *analyzer, fzl_node_t *block_node);
fzl_an_res_t analyze_return(fzl_analyzer_t *analyzer, fzl_node_t *ret_node);
fzl_an_ctx_t *an_nest_ctx(fzl_analyzer_t *analyzer, fzl_an_ctx_type_t type);
fzl_an_ctx_t *an_fin_ctx(fzl_analyzer_t *analyzer);
+47
View File
@@ -1,11 +1,16 @@
#include <common/fzl_types.h>
#include <compiler/fzl_analyzer.h>
#include <compiler/fzl_parser.h>
#include <compiler/fzl_token.h>
#include <stddef.h>
#include <stdio.h>
char block_problem[256];
Review

Also replace this "per-analyzer-buffers" with single one in other "an_*.c" files

Also replace this "per-analyzer-buffers" with single one in other "an_*.c" files
// defined in `compiler/analyzer/utility.c`
extern fzl_type_t an_toktotype(fzl_token_t *tok);
extern char *an_typetostr(fzl_type_t type, char *classname);
// Analyze block
fzl_an_res_t analyze_block(fzl_analyzer_t *analyzer, fzl_node_t *block_node)
{
2
@@ -38,6 +43,48 @@ fzl_an_res_t analyze_block(fzl_analyzer_t *analyzer, fzl_node_t *block_node)
has_return = true;
}
fzl_an_ctx_t *fnctx = analyzer->ctx;
while (fnctx != NULL)
{
if (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(block_problem, sizeof(block_problem),
"expected 'return <%s>' in function because return type is %s",
Review

"expect 'return <%s>' inside function with non-null return type"

"expect 'return <%s>' inside function with non-null return type"
rettype_str, rettype_str);
an_push_error(analyzer, block_node->token, block_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)
{
snprintf(block_problem, sizeof(block_problem),
"expected last statement in block to be 'return <%s>'",
rettype_str);
an_push_error(analyzer, last_node->token, block_problem);
return (fzl_an_res_t){.error = true};
}
}
}
an_fin_ctx(analyzer);
return (fzl_an_res_t){.error = error, .type = FZL_TYPE_NULL};
+4
View File
@@ -11,6 +11,10 @@ fzl_an_res_t analyze_common(fzl_analyzer_t *analyzer, fzl_node_t *node)
fzl_an_res_t res = {.error = false, .type = FZL_TYPE_NULL, .classname = NULL};
switch (node->type)
{
case FZL_NODETYPE_RETURN:
res = analyze_return(analyzer, node);
break;
case FZL_NODETYPE_FUNCTION:
res = analyze_function(analyzer, node);
break;
+70
View File
@@ -0,0 +1,70 @@
#include "common/fzl_types.h"
#include <compiler/fzl_analyzer.h>
#include <compiler/fzl_parser.h>
#include <compiler/fzl_token.h>
#include <stdio.h>
char ret_problem[256];
// defined in `compiler/analyzer/utility.c`
extern bool an_is_compatible(fzl_type_t a, fzl_type_t b, char *ac, char *bc);
extern fzl_type_t an_toktotype(fzl_token_t *tok);
extern char *an_typetostr(fzl_type_t type, char *classname);
// Analyze return statement
fzl_an_res_t analyze_return(fzl_analyzer_t *analyzer, fzl_node_t *ret_node)
{
if (!analyzer)
return (fzl_an_res_t){.error = true};
if (!ret_node || ret_node->type != FZL_NODETYPE_RETURN)
{
an_push_error(analyzer, NULL, "node is not typeof RETURN");
return (fzl_an_res_t){.error = false};
}
fzl_an_ctx_t *fnctx = analyzer->ctx;
while (!fnctx)
{
if (fnctx->type == FZL_AN_CTX_TYPE_FUNCTION)
break;
fnctx = fnctx->parent;
}
if (!fnctx)
{
an_push_error(analyzer, ret_node->token,
"cannot use 'return' outside function");
return (fzl_an_res_t){.error = true};
}
fzl_type_t rettype = an_toktotype(fnctx->fn->fn.type);
char *classname = NULL;
if (rettype == FZL_TYPE_OBJECT)
classname = (char *)fnctx->fn->fn.type->value;
char *rettype_str = an_typetostr(rettype, classname);
if (rettype != FZL_TYPE_NULL)
{
if (ret_node->ret.value == NULL)
{
an_push_error(analyzer, ret_node->token,
"return must be used with value in this function");
return (fzl_an_res_t){.error = true};
}
fzl_an_res_t ret_res = analyze_common(analyzer, ret_node->ret.value);
if (!an_is_compatible(ret_res.type, rettype, ret_res.classname, classname))
{
snprintf(ret_problem, sizeof(ret_problem),
"expected 'return <%s>' instead of 'return <%s>'", rettype_str,
an_typetostr(ret_res.type, ret_res.classname));
an_push_error(analyzer, ret_node->token, ret_problem);
return (fzl_an_res_t){.error = true};
}
}
return (fzl_an_res_t){
.error = false, .type = rettype, .classname = classname};
}