#include #include #include #include #include #include #include #include #include fzl_an_res_t analyze_function(fzl_analyzer_t *analyzer, fzl_node_t *fn_node) { if (!analyzer) return (fzl_an_res_t){.error = true}; if (!fn_node || fn_node->type != FZL_NODETYPE_FUNCTION) { an_push_error(analyzer, NULL, "node is not a function"); return (fzl_an_res_t){.error = true}; } fzl_an_ctx_t *fnctx = an_nest_ctx(analyzer, FZL_AN_CTX_TYPE_FUNCTION); fnctx->fn = fn_node; for (size_t i = 0; i < fn_node->fn.args_count; i++) { fzl_an_res_t res = analyze_common(analyzer, fn_node->fn.args[i]); if (res.error) return (fzl_an_res_t){.error = true}; } fzl_an_ctx_t *ctx = analyzer->ctx; while (ctx != NULL) { if (ctx->type == FZL_AN_CTX_TYPE_CLASS) break; ctx = ctx->parent; } 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; if (ctx != NULL && ctx->type == FZL_AN_CTX_TYPE_CLASS) { for (size_t i = 0; i < fn_node->fn.args_count; i++) { fzl_node_t *decl = fn_node->fn.args[i]; if (decl->type != FZL_NODETYPE_DECLARATION) { an_push_error(analyzer, decl->token, "argument must be a declaration"); an_fin_ctx(analyzer); return (fzl_an_res_t){.error = true}; } char *argname = (char *)decl->var.identifier->token->value; if (strcmp(argname, "this") == 0 && i > 0) { an_push_error(analyzer, decl->token, "manual declaration of 'this' is not allowed in methods"); an_fin_ctx(analyzer); return (fzl_an_res_t){.error = true}; } } size_t classname_len = strlen(ctx->classname); size_t methodname_len = strlen((char *)fn_node->fn.name->value); char *methodname = malloc(classname_len + methodname_len + 2); strcpy(methodname, ctx->classname); methodname[classname_len] = '_'; strcpy(methodname + classname_len + 1, fn_node->fn.name->value); methodname[classname_len + methodname_len + 1] = 0; analyzer->alloc_names[analyzer->alloc_names_top++] = methodname; fzl_symtable_res_t putres = fzl_symt_put(analyzer->symbols[ctx->symbols_level - 1], fn_node, methodname, rettype, 0); if (putres != FZL_SYMTABLE_RESULT_OK) { if (putres == FZL_SYMTABLE_RESULT_EXISTS) { snprintf(an_problem, sizeof(an_problem), "method '%s.%s' already has been declared", classname, (char *)fn_node->fn.name->value); an_push_error(analyzer, fn_node->token, an_problem); } else an_push_error(analyzer, fn_node->token, "failed to store method"); free(analyzer->alloc_names[--analyzer->alloc_names_top]); an_fin_ctx(analyzer); return (fzl_an_res_t){.error = true}; } fzl_symt_setobjclass(analyzer->symbols[ctx->symbols_level - 1], methodname, classname); } else { fzl_symtable_res_t putres = fzl_symt_put(analyzer->symbols[analyzer->symbols_top - 2], fn_node, (char *)fn_node->fn.name->value, rettype, 0); if (putres != FZL_SYMTABLE_RESULT_OK) { if (putres == FZL_SYMTABLE_RESULT_EXISTS) { snprintf(an_problem, sizeof(an_problem), "function '%s' already has been declared", (char *)fn_node->fn.name->value); an_push_error(analyzer, fn_node->token, an_problem); } else an_push_error(analyzer, fn_node->token, "failed to store function"); free(analyzer->alloc_names[--analyzer->alloc_names_top]); an_fin_ctx(analyzer); return (fzl_an_res_t){.error = true}; } } fzl_an_res_t body_res = analyze_common(analyzer, fn_node->fn.body); an_fin_ctx(analyzer); return (fzl_an_res_t){ .error = body_res.error, .type = rettype, .classname = classname}; }