From d7630dbb6a77a30470619f589ba2366390fcf293 Mon Sep 17 00:00:00 2001 From: samsonium Date: Mon, 26 Oct 2026 22:20:09 +0300 Subject: [PATCH] wip: working on analyzer - Feat: implement return analyzer - Fix: add block return check if inside function --- include/compiler/fzl_analyzer.h | 6 +++ src/compiler/analyzer/an_block.c | 47 +++++++++++++++++++++ src/compiler/analyzer/an_common.c | 4 ++ src/compiler/analyzer/an_return.c | 70 +++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 src/compiler/analyzer/an_return.c diff --git a/include/compiler/fzl_analyzer.h b/include/compiler/fzl_analyzer.h index 546b140..5b727f3 100644 --- a/include/compiler/fzl_analyzer.h +++ b/include/compiler/fzl_analyzer.h @@ -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); diff --git a/src/compiler/analyzer/an_block.c b/src/compiler/analyzer/an_block.c index 9a88b35..aad92d5 100644 --- a/src/compiler/analyzer/an_block.c +++ b/src/compiler/analyzer/an_block.c @@ -1,11 +1,16 @@ #include #include #include +#include #include #include char block_problem[256]; +// 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) { @@ -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", + 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}; diff --git a/src/compiler/analyzer/an_common.c b/src/compiler/analyzer/an_common.c index 490c6c9..4b837c8 100644 --- a/src/compiler/analyzer/an_common.c +++ b/src/compiler/analyzer/an_common.c @@ -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; diff --git a/src/compiler/analyzer/an_return.c b/src/compiler/analyzer/an_return.c new file mode 100644 index 0000000..e2a285a --- /dev/null +++ b/src/compiler/analyzer/an_return.c @@ -0,0 +1,70 @@ +#include "common/fzl_types.h" +#include +#include +#include +#include + +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}; +}