#include #include #include #include #include #include #include #include #include #include // Call definition // NOTE: split by call type (builtin/declared/extern) gen_res_t gen_call(fzl_gen_t *gen, fzl_node_t *node) { if (!gen || !node) return gen_error; // `printline(x)` builtin function if (strcmp(node->token->value, "printline") == 0) { if (node->call.args_count > 0) for (size_t i = 0; i < node->call.args_count; i++) if (gen_common(gen, node->call.args[i]).error) return gen_error; gen_op(gen, FZL_OPCODE_CALL_BUILTIN); gen_word(gen, FZL_BUILTIN_PRINTLINE); if (node->call.args_count < 1) return gen_error; return gen_ok_null; } // `exit(x?)` builtin function if (strcmp(node->token->value, "exit") == 0) { if (node->call.args_count > 0) { for (size_t i = 0; i < node->call.args_count; i++) if (gen_common(gen, node->call.args[i]).error) return gen_error; gen_op(gen, FZL_OPCODE_CALL_BUILTIN); gen_word(gen, FZL_BUILTIN_EXIT); if (node->call.args_count < 1) return gen_error; } return gen_ok_null; } if (node->call.callee->type == FZL_NODETYPE_IDENTIFIER) { if (node->call.args_count > 0) for (size_t i = 0; i < node->call.args_count; i++) if (gen_common(gen, node->call.args[i]).error) return gen_error; char *name = (char *)node->token->value; fzl_sym_t sym; bool found = gen_resolve_name(gen, name, &sym); if (!found) return gen_error; if (sym.node->type == FZL_NODETYPE_EXTERN_FN) { size_t fn_n = 0; fzl_extern_fn_t *fn = NULL; for (size_t i = 0; i < gen->extern_fns_count; i++) { if (strcmp(gen->extern_fns[i].used_name, name) == 0) { fn = &gen->extern_fns[i]; fn_n = i; break; } } if (!fn) return gen_error; fzl_type_t rettype; char *rettypecn = NULL; if (!fn->has_return) { rettype = FZL_TYPE_NULL; } else if (fn->ret_type.is_primitive) { rettype = fn->ret_type.primitive; } else { fzl_extern_type_t *type = &gen->extern_types[fn->ret_type.type_slot]; switch (type->kind) { case FZL_EXTERN_KIND_REF: rettype = FZL_TYPE_HANDLE; rettypecn = type->name; break; case FZL_EXTERN_KIND_STRUCT: rettype = FZL_TYPE_STRUCT; rettypecn = type->name; break; case FZL_EXTERN_KIND_HANDLE: rettype = FZL_TYPE_HANDLE; rettypecn = type->name; break; case FZL_EXTERN_KIND_ALIAS: if (type->alias_target.is_primitive) { rettype = type->alias_target.primitive; } else { fzl_extern_type_t *aliased = &gen->extern_types[type->alias_target.type_slot]; switch (aliased->kind) { case FZL_EXTERN_KIND_ALIAS: return gen_error; case FZL_EXTERN_KIND_HANDLE: rettype = FZL_TYPE_HANDLE; rettypecn = aliased->name; break; case FZL_EXTERN_KIND_STRUCT: rettype = FZL_TYPE_STRUCT; rettypecn = aliased->name; break; case FZL_EXTERN_KIND_REF: rettype = FZL_TYPE_HANDLE; rettypecn = aliased->name; break; default: return gen_error; } } break; default: return gen_error; } } gen_op(gen, FZL_OPCODE_CALL_EXTERN); gen_word(gen, fn_n); return (gen_res_t){ .error = false, .type = rettype, .classname = rettypecn}; } else { if (!sym.ip) return gen_error; gen_op(gen, FZL_OPCODE_CALL); gen_word(gen, sym.ip); return (gen_res_t){ .error = false, .type = sym.type, .classname = sym.classname}; } } if (node->call.callee->type == FZL_NODETYPE_FIELD) { fzl_node_t *parent_node = node->call.callee->memb.parent; fzl_node_t *method_node = node->call.callee->memb.field; gen_res_t parent_res = gen_common(gen, parent_node); if (parent_res.error) return gen_error; if (parent_res.type != FZL_TYPE_OBJECT || !parent_res.classname) return gen_error; char *classname = parent_res.classname; bool class_exists = false; for (size_t i = 0; i < gen->classes_count; i++) { if (strcmp(classname, gen->classes[i]->name) == 0) { class_exists = true; break; } } if (!class_exists) return gen_error; size_t classlen = strlen(classname); size_t fnlen = strlen(method_node->token->value); char *methodname = malloc(classlen + fnlen + 2); strcpy(methodname, classname); strcpy((methodname + classlen + 1), method_node->token->value); methodname[classlen] = '_'; methodname[classlen + fnlen + 1] = 0; fzl_sym_t fn_sym; bool found_method = false; for (ssize_t i = gen->syms_top - 1; i >= 0; i--) if ((found_method = fzl_symt_get(gen->syms[i], methodname, &fn_sym))) break; free(methodname); if (!found_method) return gen_error; if (node->call.args_count > 0) for (size_t i = 0; i < node->call.args_count; i++) if (gen_common(gen, node->call.args[i]).error) return gen_error; gen_op(gen, FZL_OPCODE_CALL); gen_word(gen, fn_sym.ip); return (gen_res_t){ .error = false, .type = fn_sym.type, .classname = fn_sym.classname}; } return gen_error; }