From a4aa220cfaf48283ffe491a6e64f4a9859fa8ade Mon Sep 17 00:00:00 2001 From: samsonium Date: Sat, 31 Oct 2026 01:58:10 +0300 Subject: [PATCH] feat: implement extern block analyzer --- CMakeLists.txt | 1 + include/compiler/internals/analyzer.h | 4 ++- src/compiler/analyzer/an_block.c | 12 ++++++- src/compiler/analyzer/an_call.c | 23 ++++++++++-- src/compiler/analyzer/an_common.c | 11 +++++- src/compiler/analyzer/an_declaration.c | 17 ++++++--- src/compiler/analyzer/an_extern.c | 50 ++++++++++++++++++++++++++ src/compiler/analyzer/an_externfn.c | 12 ++++--- src/compiler/analyzer/an_field.c | 15 ++++++-- src/compiler/analyzer/an_function.c | 12 ++++++- src/compiler/analyzer/an_loop.c | 13 +++++-- src/compiler/analyzer/an_ref.c | 4 +-- src/compiler/analyzer/an_return.c | 13 ++++++- src/compiler/analyzer/an_struct.c | 4 +++ src/compiler/analyzer/an_typedef.c | 9 ++--- src/compiler/analyzer/utility.c | 24 +++++++++++-- 16 files changed, 197 insertions(+), 27 deletions(-) create mode 100644 src/compiler/analyzer/an_extern.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e0b5ddc..56c4072 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,7 @@ if (NOT FZL_SKIP_C) src/compiler/analyzer/an_conditional.c src/compiler/analyzer/an_construct.c src/compiler/analyzer/an_declaration.c + src/compiler/analyzer/an_extern.c src/compiler/analyzer/an_externfn.c src/compiler/analyzer/an_field.c src/compiler/analyzer/an_function.c diff --git a/include/compiler/internals/analyzer.h b/include/compiler/internals/analyzer.h index d830ed7..3281d7b 100644 --- a/include/compiler/internals/analyzer.h +++ b/include/compiler/internals/analyzer.h @@ -11,7 +11,8 @@ extern char an_problem[256]; bool an_is_compatible(fzl_type_t a, fzl_type_t b, char *ac, char *bc); char *an_typetostr(fzl_type_t type, char *classname); -fzl_type_t an_toktotype(fzl_token_t *tok); +fzl_type_t an_toktotype(fzl_analyzer_t *analyzer, fzl_token_t *tok, + bool *sym_found); fzl_an_res_t analyze_common(fzl_analyzer_t *analyzer, fzl_node_t *node); fzl_an_res_t analyze_call(fzl_analyzer_t *analyzer, fzl_node_t *call_node); @@ -36,6 +37,7 @@ fzl_an_res_t analyze_typedef(fzl_analyzer_t *analyzer, fzl_node_t *td_node); fzl_an_res_t analyze_struct(fzl_analyzer_t *analyzer, fzl_node_t *struct_node); fzl_an_res_t analyze_ref(fzl_analyzer_t *analyzer, fzl_node_t *ref_node); fzl_an_res_t analyze_externfn(fzl_analyzer_t *analyzer, fzl_node_t *externfn); +fzl_an_res_t analyze_extern(fzl_analyzer_t *analyzer, fzl_node_t *extern_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 a49972e..f1f53d9 100644 --- a/src/compiler/analyzer/an_block.c +++ b/src/compiler/analyzer/an_block.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -49,10 +50,19 @@ fzl_an_res_t analyze_block(fzl_analyzer_t *analyzer, fzl_node_t *block_node) if (fnctx && fnctx->type == FZL_AN_CTX_TYPE_FUNCTION) { - fzl_type_t rettype = an_toktotype(fnctx->fn->fn.type); + bool found = false; + fzl_type_t rettype = an_toktotype(analyzer, fnctx->fn->fn.type, &found); char *classname = NULL; char *rettype_str = an_typetostr(rettype, classname); + if (!found) + { + snprintf(an_problem, sizeof(an_problem), "symbol '%s' not found", + (char *)fnctx->fn->fn.type->value); + an_push_error(analyzer, fnctx->fn->fn.type, an_problem); + return (fzl_an_res_t){.error = true}; + } + if (rettype == FZL_TYPE_OBJECT) classname = (char *)fnctx->fn->fn.type->value; diff --git a/src/compiler/analyzer/an_call.c b/src/compiler/analyzer/an_call.c index 7d7048c..e347dff 100644 --- a/src/compiler/analyzer/an_call.c +++ b/src/compiler/analyzer/an_call.c @@ -177,8 +177,18 @@ fzl_an_res_t analyze_call(fzl_analyzer_t *analyzer, fzl_node_t *call_node) for (size_t i = offset; i < sym.node->fn.args_count; i++) { fzl_node_t *arg = sym.node->fn.args[i]; - fzl_type_t req_type = an_toktotype(arg->var.type); + bool found = false; + fzl_type_t req_type = an_toktotype(analyzer, arg->var.type, &found); char *req_classname = NULL; + + if (!found) + { + snprintf(an_problem, sizeof(an_problem), "symbol '%s' not found", + (char *)arg->var.type->value); + an_push_error(analyzer, arg->var.type, an_problem); + return (fzl_an_res_t){.error = true}; + } + if (req_type == FZL_TYPE_OBJECT) req_classname = arg->var.type->value; @@ -226,9 +236,18 @@ fzl_an_res_t analyze_call(fzl_analyzer_t *analyzer, fzl_node_t *call_node) } } - fzl_type_t type = an_toktotype(sym.node->fn.type); + bool type_found = false; + fzl_type_t type = an_toktotype(analyzer, sym.node->fn.type, &type_found); char *classname = sym.classname; + if (!type_found) + { + snprintf(an_problem, sizeof(an_problem), "symbol '%s' not found", + (char *)sym.node->fn.type->value); + an_push_error(analyzer, sym.node->fn.type, an_problem); + return (fzl_an_res_t){.error = true}; + } + if (tmp_method_name != NULL) { free(tmp_method_name); diff --git a/src/compiler/analyzer/an_common.c b/src/compiler/analyzer/an_common.c index e7955e1..929162f 100644 --- a/src/compiler/analyzer/an_common.c +++ b/src/compiler/analyzer/an_common.c @@ -4,6 +4,7 @@ #include #include #include +#include #include // Analyzer main function @@ -15,6 +16,14 @@ 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_EXTERN: + res = analyze_extern(analyzer, node); + break; + + case FZL_NODETYPE_EXTERN_FN: + res = analyze_externfn(analyzer, node); + break; + case FZL_NODETYPE_REFERENCE: res = analyze_ref(analyzer, node); break; @@ -24,7 +33,7 @@ fzl_an_res_t analyze_common(fzl_analyzer_t *analyzer, fzl_node_t *node) break; case FZL_NODETYPE_ALIAS: - res.type = an_toktotype(node->token); + res.type = an_toktotype(analyzer, node->token, NULL); break; case FZL_NODETYPE_HANDLE: diff --git a/src/compiler/analyzer/an_declaration.c b/src/compiler/analyzer/an_declaration.c index fcabeec..52e1a8b 100644 --- a/src/compiler/analyzer/an_declaration.c +++ b/src/compiler/analyzer/an_declaration.c @@ -20,14 +20,23 @@ fzl_an_res_t analyze_declaration(fzl_analyzer_t *analyzer, fzl_node_t *decl) } char *name = (char *)decl->var.identifier->token->value; - fzl_type_t type = an_toktotype(decl->var.type); + bool type_found = false; + fzl_type_t type = an_toktotype(analyzer, decl->var.type, &type_found); + + if (!type_found) + { + snprintf(an_problem, sizeof(an_problem), "symbol '%s' not found", + (char *)decl->var.type->value); + an_push_error(analyzer, decl->var.type, an_problem); + return (fzl_an_res_t){.error = true}; + } + char *classname = NULL; if (type == FZL_TYPE_OBJECT) classname = decl->var.type->value; - fzl_symtable_res_t res = - fzl_symt_put(analyzer->symbols[analyzer->symbols_top - 1], decl, name, - an_toktotype(decl->var.type), 0); + fzl_symtable_res_t res = fzl_symt_put( + analyzer->symbols[analyzer->symbols_top - 1], decl, name, type, 0); if (res != FZL_SYMTABLE_RESULT_OK) { if (res == FZL_SYMTABLE_RESULT_EXISTS) diff --git a/src/compiler/analyzer/an_extern.c b/src/compiler/analyzer/an_extern.c new file mode 100644 index 0000000..d79e8dc --- /dev/null +++ b/src/compiler/analyzer/an_extern.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include + +// Analyze extern block definition +fzl_an_res_t analyze_extern(fzl_analyzer_t *analyzer, fzl_node_t *extern_node) +{ + if (!analyzer) + return (fzl_an_res_t){.error = true}; + + if (!extern_node || extern_node->type != FZL_NODETYPE_EXTERN) + { + an_push_error(analyzer, NULL, "node is not an extern block"); + return (fzl_an_res_t){.error = true}; + } + + if (extern_node->ext.typedefs_count < 1 && extern_node->ext.fns_count < 1) + an_push_warning(analyzer, extern_node->token, "extern is empty"); + + for (size_t i = 0; i < extern_node->ext.typedefs_count; i++) + { + fzl_node_t *node = extern_node->ext.typedefs[i]; + fzl_an_res_t res = analyze_common(analyzer, node); + if (res.error) + return (fzl_an_res_t){.error = true}; + + if (node->type != FZL_NODETYPE_TYPEDEF && + node->type != FZL_NODETYPE_EXTERN_FN) + { + snprintf(an_problem, sizeof(an_problem), + "unexpected statement '%s' inside extern block", + (char *)node->token->value); + an_push_error(analyzer, node->token, an_problem); + return (fzl_an_res_t){.error = true}; + } + } + + for (size_t i = 0; i < extern_node->ext.fns_count; i++) + { + fzl_an_res_t res = analyze_common(analyzer, extern_node->ext.fns[i]); + if (res.error) + return (fzl_an_res_t){.error = true}; + } + + return (fzl_an_res_t){ + .error = false, .type = FZL_TYPE_NULL, .classname = NULL}; +} diff --git a/src/compiler/analyzer/an_externfn.c b/src/compiler/analyzer/an_externfn.c index 85648d6..799421e 100644 --- a/src/compiler/analyzer/an_externfn.c +++ b/src/compiler/analyzer/an_externfn.c @@ -1,9 +1,9 @@ -#include "common/fzl_types.h" -#include "compiler/fzl_parser.h" -#include "compiler/fzl_token.h" -#include "compiler/utils/fzl_symtable.h" +#include #include +#include +#include #include +#include #include #include #include @@ -20,6 +20,8 @@ fzl_an_res_t analyze_externfn(fzl_analyzer_t *analyzer, fzl_node_t *externfn) return (fzl_an_res_t){.error = true}; } + an_nest_ctx(analyzer, FZL_AN_CTX_TYPE_UNNECESSARY); + for (size_t i = 0; i < externfn->ext_fn.args_count; i++) { fzl_an_res_t res = analyze_common(analyzer, externfn->ext_fn.args[i]); @@ -70,6 +72,8 @@ fzl_an_res_t analyze_externfn(fzl_analyzer_t *analyzer, fzl_node_t *externfn) return (fzl_an_res_t){.error = true}; } + an_fin_ctx(analyzer); + return (fzl_an_res_t){ .error = false, .type = FZL_TYPE_EXTERN_FN, .classname = NULL}; } diff --git a/src/compiler/analyzer/an_field.c b/src/compiler/analyzer/an_field.c index b95dc72..8de3464 100644 --- a/src/compiler/analyzer/an_field.c +++ b/src/compiler/analyzer/an_field.c @@ -69,8 +69,19 @@ fzl_an_res_t analyze_field(fzl_analyzer_t *analyzer, fzl_node_t *field) return (fzl_an_res_t){.error = true}; } - fzl_type_t field_type = an_toktotype(field_node->var.type); - char *classname = NULL; + bool type_found = false; + fzl_type_t field_type = + an_toktotype(analyzer, field_node->var.type, &type_found); + + if (!type_found) + { + snprintf(an_problem, sizeof(an_problem), "symbol '%s' not found", + (char *)field_node->var.type->value); + an_push_error(analyzer, field_node->var.type, an_problem); + return (fzl_an_res_t){.error = true}; + } + + char *classname = NULL; if (field_type == FZL_TYPE_OBJECT) classname = field_node->var.type->value; diff --git a/src/compiler/analyzer/an_function.c b/src/compiler/analyzer/an_function.c index 90209b6..2ae2130 100644 --- a/src/compiler/analyzer/an_function.c +++ b/src/compiler/analyzer/an_function.c @@ -38,8 +38,18 @@ fzl_an_res_t analyze_function(fzl_analyzer_t *analyzer, fzl_node_t *fn_node) ctx = ctx->parent; } - fzl_type_t rettype = an_toktotype(fn_node->fn.type); + bool type_found = false; + fzl_type_t rettype = an_toktotype(analyzer, fn_node->fn.type, &type_found); char *classname = NULL; + + if (!type_found) + { + snprintf(an_problem, sizeof(an_problem), "symbol '%s' not found", + (char *)fn_node->fn.type->value); + an_push_error(analyzer, fn_node->fn.type, an_problem); + return (fzl_an_res_t){.error = true}; + } + if (rettype == FZL_TYPE_OBJECT) classname = (char *)fn_node->fn.type->value; diff --git a/src/compiler/analyzer/an_loop.c b/src/compiler/analyzer/an_loop.c index 77aabbf..a2f575b 100644 --- a/src/compiler/analyzer/an_loop.c +++ b/src/compiler/analyzer/an_loop.c @@ -49,9 +49,18 @@ init_analysis check_init(fzl_analyzer_t *analyzer, fzl_node_t *init) } else if (init->type == FZL_NODETYPE_DECLARATION) { - char *name = init->var.identifier->token->value; - fzl_type_t type = an_toktotype(init->var.type); + char *name = init->var.identifier->token->value; + + bool type_found = false; + fzl_type_t type = an_toktotype(analyzer, init->var.type, &type_found); char *classname = NULL; + + if (!type_found) + { + snprintf(an_problem, sizeof(an_problem), "symbol '%s' not found", + (char *)init->var.type->value); + } + if (type == FZL_TYPE_OBJECT) classname = init->var.type->value; diff --git a/src/compiler/analyzer/an_ref.c b/src/compiler/analyzer/an_ref.c index fc40bbc..fe5c070 100644 --- a/src/compiler/analyzer/an_ref.c +++ b/src/compiler/analyzer/an_ref.c @@ -12,9 +12,9 @@ fzl_an_res_t analyze_ref(fzl_analyzer_t *analyzer, fzl_node_t *ref_node) if (!analyzer) return (fzl_an_res_t){.error = true}; - if (!ref_node || ref_node->type != FZL_NODETYPE_STRUCT) + if (!ref_node || ref_node->type != FZL_NODETYPE_REFERENCE) { - an_push_error(analyzer, NULL, "node is not a structure"); + an_push_error(analyzer, NULL, "node is not a reference"); return (fzl_an_res_t){.error = true}; } diff --git a/src/compiler/analyzer/an_return.c b/src/compiler/analyzer/an_return.c index 8ebc2f5..839658a 100644 --- a/src/compiler/analyzer/an_return.c +++ b/src/compiler/analyzer/an_return.c @@ -3,6 +3,7 @@ #include #include #include +#include #include // Analyze return statement @@ -45,8 +46,18 @@ fzl_an_res_t analyze_return(fzl_analyzer_t *analyzer, fzl_node_t *ret_node) return (fzl_an_res_t){.error = true}; } - fzl_type_t rettype = an_toktotype(fnctx->fn->fn.type); + bool type_found = false; + fzl_type_t rettype = an_toktotype(analyzer, fnctx->fn->fn.type, &type_found); char *classname = NULL; + + if (!type_found) + { + snprintf(an_problem, sizeof(an_problem), "symbol '%s' not found", + (char *)fnctx->fn->fn.type->value); + an_push_error(analyzer, fnctx->fn->fn.type, an_problem); + return (fzl_an_res_t){.error = true}; + } + if (rettype == FZL_TYPE_OBJECT) classname = (char *)fnctx->fn->fn.type->value; diff --git a/src/compiler/analyzer/an_struct.c b/src/compiler/analyzer/an_struct.c index 6eb5e67..d8bc2f8 100644 --- a/src/compiler/analyzer/an_struct.c +++ b/src/compiler/analyzer/an_struct.c @@ -17,6 +17,8 @@ fzl_an_res_t analyze_struct(fzl_analyzer_t *analyzer, fzl_node_t *struct_node) return (fzl_an_res_t){.error = true}; } + an_nest_ctx(analyzer, FZL_AN_CTX_TYPE_UNNECESSARY); + if (struct_node->structure.entries_count < 1) { an_push_warning(analyzer, struct_node->token, "empty structure"); @@ -47,6 +49,8 @@ fzl_an_res_t analyze_struct(fzl_analyzer_t *analyzer, fzl_node_t *struct_node) } } + an_fin_ctx(analyzer); + return (fzl_an_res_t){ .error = false, .type = FZL_TYPE_STRUCT, .classname = NULL}; } diff --git a/src/compiler/analyzer/an_typedef.c b/src/compiler/analyzer/an_typedef.c index 2dc074e..3c794b4 100644 --- a/src/compiler/analyzer/an_typedef.c +++ b/src/compiler/analyzer/an_typedef.c @@ -22,11 +22,12 @@ fzl_an_res_t analyze_typedef(fzl_analyzer_t *analyzer, fzl_node_t *td_node) fzl_nodetype_t type = td_node->typedefinition.type->type; if (type != FZL_NODETYPE_ALIAS && type != FZL_NODETYPE_STRUCT && - type != FZL_NODETYPE_HANDLE) + type != FZL_NODETYPE_HANDLE && type != FZL_NODETYPE_REFERENCE) { - an_push_error(analyzer, td_node->token, - "only alias, structure and handle are allowed in type " - "definition value"); + an_push_error( + analyzer, td_node->token, + "only alias, structure, reference and handle are allowed in type " + "definition value"); return (fzl_an_res_t){.error = true}; } diff --git a/src/compiler/analyzer/utility.c b/src/compiler/analyzer/utility.c index db4792e..d6a7401 100644 --- a/src/compiler/analyzer/utility.c +++ b/src/compiler/analyzer/utility.c @@ -1,6 +1,9 @@ #include +#include #include +#include #include +#include #include // Check compatibility between A and B types (and classnames) @@ -79,13 +82,30 @@ char *an_typetostr(fzl_type_t type, char *classname) } // Convert type token to type -fzl_type_t an_toktotype(fzl_token_t *tok) +fzl_type_t an_toktotype(fzl_analyzer_t *analyzer, fzl_token_t *tok, + bool *sym_found) { if (!tok) return FZL_TYPE_NULL; if (tok->type == FZL_TOKTYPE_NAME) - return FZL_TYPE_OBJECT; + { + fzl_sym_t sym; + bool found = false; + for (ssize_t i = analyzer->symbols_top - 1; i >= 0; i--) + { + if ((found = fzl_symt_get(analyzer->symbols[i], tok->value, &sym))) + break; + } + + if (sym_found) + *sym_found = found; + + return found ? sym.type : FZL_TYPE_NULL; + } + + if (sym_found) + *sym_found = true; if (strcmp(tok->value, "null") == 0) return FZL_TYPE_NULL;