/** * @file function.c * @brief Function implementation for Baba Yaga * @author eli_oat * @version 0.0.1 * @date 2025 * * This file implements the function system for the Baba Yaga language. * Functions support closures, partial application, and first-class behavior. */ #include #include #include #include "baba_yaga.h" /* Forward declarations */ extern Scope* scope_create(Scope* parent); extern void scope_destroy(Scope* scope); extern bool scope_define(Scope* scope, const char* name, Value value, bool is_constant); extern Value interpreter_evaluate_expression(void* node, Scope* scope); /* ============================================================================ * Function Structure Definitions * ============================================================================ */ /** * @brief Function parameter */ typedef struct { char* name; /**< Parameter name */ bool is_optional; /**< Whether parameter is optional */ } FunctionParam; typedef enum { FUNC_NATIVE, /**< Native C function */ FUNC_USER /**< User-defined function */ } FunctionType; /** * @brief Function body (placeholder for AST node) */ typedef struct { void* ast_node; /**< AST node representing function body */ char* source; /**< Source code for debugging */ } FunctionBody; /** * @brief Function value structure */ typedef struct { char* name; /**< Function name (can be NULL for anonymous) */ FunctionType type; /**< Function type */ FunctionParam* params; /**< Array of parameters */ int param_count; /**< Number of parameters */ int required_params; /**< Number of required parameters */ union { Value (*native_func)(Value*, int, Scope*); /**< Native function pointer */ FunctionBody user_body; /**< User function body */ } body; void* closure_scope; /**< Closure scope (placeholder) */ int ref_count; /**< Reference count for memory management */ } FunctionValue; /* ============================================================================ * Function Creation and Management * ============================================================================ */ /* TODO: Implement parameter management functions */ /** * @brief Destroy a function body * * @param body Function body to destroy */ static void function_body_destroy(FunctionBody* body) { if (body != NULL && body->source != NULL) { free(body->source); body->source = NULL; } /* Note: ast_node cleanup will be handled by AST system */ } /* ============================================================================ * Public Function API * ============================================================================ */ Value baba_yaga_value_function(const char* name, Value (*body)(Value*, int, Scope*), int param_count, int required_param_count) { Value value; value.type = VAL_FUNCTION; FunctionValue* func_value = malloc(sizeof(FunctionValue)); if (func_value == NULL) { value.type = VAL_NIL; return value; } func_value->name = name != NULL ? strdup(name) : NULL; func_value->type = FUNC_NATIVE; func_value->param_count = param_count; func_value->required_params = required_param_count; func_value->ref_count = 1; func_value->closure_scope = NULL; /* TODO: Implement closure scope */ /* Allocate parameter array */ if (param_count > 0) { func_value->params = calloc(param_count, sizeof(FunctionParam)); if (func_value->params == NULL) { free(func_value->name); free(func_value); value.type = VAL_NIL; return value; } /* Initialize parameters with placeholder names */ for (int i = 0; i < param_count; i++) { char param_name[16]; snprintf(param_name, sizeof(param_name), "param_%d", i + 1); func_value->params[i].name = strdup(param_name); func_value->params[i].is_optional = (i >= required_param_count); } } else { func_value->params = NULL; } /* Set native function pointer */ func_value->body.native_func = body; value.data.function = func_value; return value; } Value baba_yaga_function_call(const Value* func, const Value* args, int arg_count, Scope* scope) { if (func == NULL || func->type != VAL_FUNCTION || args == NULL) { return baba_yaga_value_nil(); } FunctionValue* func_value = (FunctionValue*)func->data.function; /* Check if we have enough arguments for partial application */ if (arg_count < func_value->required_params) { /* TODO: Implement partial application */ /* For now, return a new function with fewer required parameters */ return baba_yaga_value_nil(); } /* Execute function based on type */ switch (func_value->type) { case FUNC_NATIVE: if (func_value->body.native_func != NULL) { return func_value->body.native_func((Value*)args, arg_count, scope); } break; case FUNC_USER: /* Execute user-defined function */ if (func_value->body.user_body.ast_node != NULL) { /* Create new scope for function execution */ /* According to JS team requirements: function calls create local scopes that inherit from global scope */ Scope* global_scope = scope_get_global(scope); Scope* func_scope = scope_create(global_scope); /* Pass global scope as parent for local function scope */ if (func_scope == NULL) { DEBUG_ERROR("Failed to create function scope"); return baba_yaga_value_nil(); } /* Bind parameters to arguments */ for (int i = 0; i < arg_count && i < func_value->param_count; i++) { const char* param_name = func_value->params[i].name; if (param_name != NULL) { scope_define(func_scope, param_name, args[i], false); } } /* Execute function body */ Value result = interpreter_evaluate_expression( func_value->body.user_body.ast_node, func_scope ); /* Clean up function scope */ scope_destroy(func_scope); return result; } break; } return baba_yaga_value_nil(); } /* ============================================================================ * Internal Function Management * ============================================================================ */ /** * @brief Increment reference count for a function * * @param func Function value */ void function_increment_ref(Value* func) { if (func != NULL && func->type == VAL_FUNCTION) { FunctionValue* func_value = (FunctionValue*)func->data.function; func_value->ref_count++; } } /** * @brief Decrement reference count for a function * * @param func Function value */ void function_decrement_ref(Value* func) { if (func != NULL && func->type == VAL_FUNCTION) { FunctionValue* func_value = (FunctionValue*)func->data.function; func_value->ref_count--; if (func_value->ref_count <= 0) { /* Clean up function */ free(func_value->name); /* Clean up parameters */ if (func_value->params != NULL) { for (int i = 0; i < func_value->param_count; i++) { free(func_value->params[i].name); } free(func_value->params); } /* Clean up function body */ if (func_value->type == FUNC_USER) { function_body_destroy(&func_value->body.user_body); } /* TODO: Clean up closure scope */ free(func_value); } } } /* ============================================================================ * Function Utility Functions * ============================================================================ */ /** * @brief Get function name * * @param func Function value * @return Function name, or NULL if anonymous */ const char* function_get_name(const Value* func) { if (func == NULL || func->type != VAL_FUNCTION) { return NULL; } FunctionValue* func_value = (FunctionValue*)func->data.function; return func_value->name; } /** * @brief Get function parameter count * * @param func Function value * @return Number of parameters */ int function_get_param_count(const Value* func) { if (func == NULL || func->type != VAL_FUNCTION) { return 0; } FunctionValue* func_value = (FunctionValue*)func->data.function; return func_value->param_count; } /** * @brief Get function required parameter count * * @param func Function value * @return Number of required parameters */ int function_get_required_param_count(const Value* func) { if (func == NULL || func->type != VAL_FUNCTION) { return 0; } FunctionValue* func_value = (FunctionValue*)func->data.function; return func_value->required_params; }