/** * @file interpreter.c * @brief Interpreter implementation for Baba Yaga * @author eli_oat * @version 0.0.1 * @date 2025 * * This file implements the main interpreter for the Baba Yaga language. */ #include #include #include #include "baba_yaga.h" /* Forward declarations for function types */ typedef struct { char* name; bool is_optional; } FunctionParam; typedef enum { FUNC_NATIVE, FUNC_USER } FunctionType; typedef struct { void* ast_node; char* source; } FunctionBody; typedef struct { char* name; FunctionType type; FunctionParam* params; int param_count; int required_params; union { Value (*native_func)(Value*, int); FunctionBody user_body; } body; void* closure_scope; int ref_count; } FunctionValue; /* Forward declarations */ Value interpreter_evaluate_expression(void* node, Scope* scope); static Value interpreter_evaluate_statement(void* node, Scope* scope); /* Standard library function declarations */ Value stdlib_table_entry(Value* args, int argc); /* ============================================================================ * Interpreter Structure * ============================================================================ */ struct Interpreter { Scope* global_scope; BabaYagaError* last_error; DebugLevel debug_level; }; /* ============================================================================ * Standard Library Registration * ============================================================================ */ /** * @brief Register standard library functions in the global scope * * @param scope Global scope to register functions in */ static void register_stdlib(Scope* scope) { DEBUG_INFO("Registering standard library functions"); /* Core combinator */ Value apply_func = baba_yaga_value_function("apply", stdlib_apply_wrapper, 10, 1); scope_define(scope, "apply", apply_func, true); /* Predefined variables for testing */ Value hello_var = baba_yaga_value_string("hello"); scope_define(scope, "hello", hello_var, true); /* Arithmetic functions */ Value add_func = baba_yaga_value_function("add", stdlib_add_wrapper, 2, 2); scope_define(scope, "add", add_func, true); Value subtract_func = baba_yaga_value_function("subtract", stdlib_subtract_wrapper, 2, 2); scope_define(scope, "subtract", subtract_func, true); Value multiply_func = baba_yaga_value_function("multiply", stdlib_multiply_wrapper, 2, 2); scope_define(scope, "multiply", multiply_func, true); Value divide_func = baba_yaga_value_function("divide", stdlib_divide_wrapper, 2, 2); scope_define(scope, "divide", divide_func, true); Value modulo_func = baba_yaga_value_function("modulo", stdlib_modulo_wrapper, 2, 2); scope_define(scope, "modulo", modulo_func, true); Value pow_func = baba_yaga_value_function("pow", stdlib_pow_wrapper, 2, 2); scope_define(scope, "pow", pow_func, true); Value negate_func = baba_yaga_value_function("negate", stdlib_negate_wrapper, 1, 1); scope_define(scope, "negate", negate_func, true); /* Comparison functions */ Value equals_func = baba_yaga_value_function("equals", stdlib_equals_wrapper, 2, 2); scope_define(scope, "equals", equals_func, true); Value not_equals_func = baba_yaga_value_function("not_equals", stdlib_not_equals_wrapper, 2, 2); scope_define(scope, "not_equals", not_equals_func, true); Value less_func = baba_yaga_value_function("less", stdlib_less_wrapper, 2, 2); scope_define(scope, "less", less_func, true); Value less_equal_func = baba_yaga_value_function("less_equal", stdlib_less_equal_wrapper, 2, 2); scope_define(scope, "less_equal", less_equal_func, true); Value greater_func = baba_yaga_value_function("greater", stdlib_greater_wrapper, 2, 2); scope_define(scope, "greater", greater_func, true); Value greater_equal_func = baba_yaga_value_function("greater_equal", stdlib_greater_equal_wrapper, 2, 2); scope_define(scope, "greater_equal", greater_equal_func, true); /* Add canonical names for JavaScript compatibility */ Value greater_than_func = baba_yaga_value_function("greaterThan", stdlib_greater_wrapper, 2, 2); scope_define(scope, "greaterThan", greater_than_func, true); Value less_than_func = baba_yaga_value_function("lessThan", stdlib_less_wrapper, 2, 2); scope_define(scope, "lessThan", less_than_func, true); Value greater_equal_than_func = baba_yaga_value_function("greaterEqual", stdlib_greater_equal_wrapper, 2, 2); scope_define(scope, "greaterEqual", greater_equal_than_func, true); Value less_equal_than_func = baba_yaga_value_function("lessEqual", stdlib_less_equal_wrapper, 2, 2); scope_define(scope, "lessEqual", less_equal_than_func, true); /* Logical functions */ Value and_func = baba_yaga_value_function("and", stdlib_and_wrapper, 2, 2); scope_define(scope, "and", and_func, true); Value or_func = baba_yaga_value_function("or", stdlib_or_wrapper, 2, 2); scope_define(scope, "or", or_func, true); Value xor_func = baba_yaga_value_function("xor", stdlib_xor_wrapper, 2, 2); scope_define(scope, "xor", xor_func, true); Value not_func = baba_yaga_value_function("not", stdlib_not_wrapper, 1, 1); scope_define(scope, "not", not_func, true); /* Function composition */ Value compose_func = baba_yaga_value_function("compose", stdlib_compose_wrapper, 4, 2); scope_define(scope, "compose", compose_func, true); /* IO functions */ Value out_func = baba_yaga_value_function("out", stdlib_out_wrapper, 1, 1); scope_define(scope, "out", out_func, true); Value in_func = baba_yaga_value_function("in", stdlib_in_wrapper, 0, 0); scope_define(scope, "in", in_func, true); Value assert_func = baba_yaga_value_function("assert", stdlib_assert_wrapper, 1, 1); scope_define(scope, "assert", assert_func, true); Value emit_func = baba_yaga_value_function("emit", stdlib_emit_wrapper, 1, 1); scope_define(scope, "emit", emit_func, true); Value listen_func = baba_yaga_value_function("listen", stdlib_listen_wrapper, 0, 0); scope_define(scope, "listen", listen_func, true); /* Higher-order functions */ Value map_func = baba_yaga_value_function("map", stdlib_map, 2, 2); scope_define(scope, "map", map_func, true); Value filter_func = baba_yaga_value_function("filter", stdlib_filter, 2, 2); scope_define(scope, "filter", filter_func, true); Value reduce_func = baba_yaga_value_function("reduce", stdlib_reduce, 3, 3); scope_define(scope, "reduce", reduce_func, true); /* Advanced combinators */ Value each_func = baba_yaga_value_function("each", stdlib_each, 3, 3); scope_define(scope, "each", each_func, true); Value flip_func = baba_yaga_value_function("flip", stdlib_flip_wrapper, 3, 1); scope_define(scope, "flip", flip_func, true); Value constant_func = baba_yaga_value_function("constant", stdlib_constant_wrapper, 2, 1); scope_define(scope, "constant", constant_func, true); /* Table operations namespace */ Value t_map_func = baba_yaga_value_function("t.map", stdlib_t_map_wrapper, 2, 2); scope_define(scope, "t.map", t_map_func, true); Value t_filter_func = baba_yaga_value_function("t.filter", stdlib_t_filter_wrapper, 2, 2); scope_define(scope, "t.filter", t_filter_func, true); Value t_reduce_func = baba_yaga_value_function("t.reduce", stdlib_t_reduce_wrapper, 3, 3); scope_define(scope, "t.reduce", t_reduce_func, true); Value t_set_func = baba_yaga_value_function("t.set", stdlib_t_set_wrapper, 3, 3); scope_define(scope, "t.set", t_set_func, true); Value t_delete_func = baba_yaga_value_function("t.delete", stdlib_t_delete_wrapper, 2, 2); scope_define(scope, "t.delete", t_delete_func, true); Value t_merge_func = baba_yaga_value_function("t.merge", stdlib_t_merge_wrapper, 2, 2); scope_define(scope, "t.merge", t_merge_func, true); Value t_length_func = baba_yaga_value_function("t.length", stdlib_t_length_wrapper, 1, 1); scope_define(scope, "t.length", t_length_func, true); Value t_has_func = baba_yaga_value_function("t.has", stdlib_t_has_wrapper, 2, 2); scope_define(scope, "t.has", t_has_func, true); Value t_get_func = baba_yaga_value_function("t.get", stdlib_t_get_wrapper, 3, 3); scope_define(scope, "t.get", t_get_func, true); /* Internal table entry function for key-value pairs */ Value table_entry_func = baba_yaga_value_function("table_entry", stdlib_table_entry_wrapper, 2, 2); scope_define(scope, "table_entry", table_entry_func, true); /* Create t namespace table */ Value t_table = baba_yaga_value_table(); t_table = baba_yaga_table_set(&t_table, "map", &t_map_func); t_table = baba_yaga_table_set(&t_table, "filter", &t_filter_func); t_table = baba_yaga_table_set(&t_table, "reduce", &t_reduce_func); t_table = baba_yaga_table_set(&t_table, "set", &t_set_func); t_table = baba_yaga_table_set(&t_table, "delete", &t_delete_func); t_table = baba_yaga_table_set(&t_table, "merge", &t_merge_func); t_table = baba_yaga_table_set(&t_table, "length", &t_length_func); t_table = baba_yaga_table_set(&t_table, "has", &t_has_func); t_table = baba_yaga_table_set(&t_table, "get", &t_get_func); scope_define(scope, "t", t_table, true); DEBUG_INFO("Registered %d standard library functions", 31); } /* ============================================================================ * Core API Functions * ============================================================================ */ Interpreter* baba_yaga_create(void) { Interpreter* interp = malloc(sizeof(Interpreter)); if (interp == NULL) { return NULL; } /* Create global scope */ interp->global_scope = scope_create(NULL); if (interp->global_scope == NULL) { free(interp); return NULL; } /* Initialize error handling */ interp->last_error = NULL; interp->debug_level = DEBUG_NONE; /* Register standard library */ register_stdlib(interp->global_scope); DEBUG_INFO("Interpreter created successfully"); return interp; } void baba_yaga_destroy(Interpreter* interp) { if (interp == NULL) { return; } /* Destroy global scope */ if (interp->global_scope != NULL) { scope_destroy(interp->global_scope); } /* Destroy last error */ if (interp->last_error != NULL) { baba_yaga_error_destroy(interp->last_error); } free(interp); DEBUG_INFO("Interpreter destroyed"); } Value baba_yaga_execute(Interpreter* interp, const char* source, size_t source_len, ExecResult* result) { if (interp == NULL || source == NULL || result == NULL) { if (result != NULL) { *result = EXEC_ERROR; } return baba_yaga_value_nil(); } DEBUG_INFO("Executing source code (length: %zu)", source_len); /* Tokenize */ void* tokens[1000]; int token_count = baba_yaga_tokenize(source, source_len, tokens, 1000); if (token_count <= 0) { DEBUG_ERROR("Failed to tokenize source code"); *result = EXEC_ERROR; return baba_yaga_value_nil(); } DEBUG_DEBUG("Tokenized into %d tokens", token_count); /* Parse */ void* ast = baba_yaga_parse(tokens, token_count); baba_yaga_free_tokens(tokens, token_count); if (ast == NULL) { DEBUG_ERROR("Failed to parse source code"); *result = EXEC_ERROR; return baba_yaga_value_nil(); } DEBUG_DEBUG("Parsed AST successfully"); if (interp->debug_level >= DEBUG_DEBUG) { printf("AST:\n"); baba_yaga_print_ast(ast, 0); } /* Execute */ Value result_value = interpreter_evaluate_expression(ast, interp->global_scope); baba_yaga_destroy_ast(ast); if (result_value.type == VAL_NIL) { *result = EXEC_ERROR; } else { *result = EXEC_SUCCESS; } DEBUG_INFO("Execution completed"); return result_value; } Value baba_yaga_execute_file(Interpreter* interp, const char* filename, ExecResult* result) { if (interp == NULL || filename == NULL || result == NULL) { if (result != NULL) { *result = EXEC_ERROR; } return baba_yaga_value_nil(); } DEBUG_INFO("Executing file: %s", filename); /* Read file */ FILE* file = fopen(filename, "r"); if (file == NULL) { DEBUG_ERROR("Failed to open file: %s", filename); *result = EXEC_ERROR; return baba_yaga_value_nil(); } /* Get file size */ fseek(file, 0, SEEK_END); long file_size = ftell(file); fseek(file, 0, SEEK_SET); if (file_size <= 0) { DEBUG_ERROR("File is empty or invalid: %s", filename); fclose(file); *result = EXEC_ERROR; return baba_yaga_value_nil(); } /* Read content */ char* source = malloc(file_size + 1); if (source == NULL) { DEBUG_ERROR("Failed to allocate memory for file content"); fclose(file); *result = EXEC_ERROR; return baba_yaga_value_nil(); } size_t bytes_read = fread(source, 1, file_size, file); source[bytes_read] = '\0'; fclose(file); /* Execute */ Value result_value = baba_yaga_execute(interp, source, bytes_read, result); free(source); return result_value; } /* ============================================================================ * Expression Evaluation * ============================================================================ */ /** * @brief Evaluate an expression node * * @param node AST node to evaluate * @param scope Current scope * @return Result value */ Value interpreter_evaluate_expression(void* node, Scope* scope) { if (node == NULL) { return baba_yaga_value_nil(); } NodeType node_type = baba_yaga_ast_get_type(node); DEBUG_DEBUG("Evaluating expression: type %d", node_type); switch (node_type) { case NODE_LITERAL: { Value literal = baba_yaga_ast_get_literal(node); DEBUG_DEBUG("Literal evaluation: type %d", literal.type); return literal; } case NODE_IDENTIFIER: { const char* identifier = baba_yaga_ast_get_identifier(node); if (identifier == NULL) { DEBUG_ERROR("Invalid identifier node"); return baba_yaga_value_nil(); } DEBUG_DEBUG("Looking up identifier: %s", identifier); /* Check if this is a function reference (starts with @) */ if (identifier[0] == '@') { /* Strip the @ prefix and look up the function */ const char* func_name = identifier + 1; DEBUG_DEBUG("Function reference: %s", func_name); Value value = scope_get(scope, func_name); DEBUG_DEBUG("Function '%s' lookup result type: %d", func_name, value.type); if (value.type == VAL_NIL) { DEBUG_ERROR("Undefined function: %s", func_name); } return value; } else { /* Regular variable lookup */ Value value = scope_get(scope, identifier); DEBUG_DEBUG("Identifier '%s' lookup result type: %d", identifier, value.type); if (value.type == VAL_NIL) { DEBUG_ERROR("Undefined variable: %s", identifier); } return value; } } case NODE_FUNCTION_CALL: { DEBUG_DEBUG("Evaluating NODE_FUNCTION_CALL"); /* Evaluate function */ void* func_node = baba_yaga_ast_get_function_call_func(node); Value func_value = interpreter_evaluate_expression(func_node, scope); DEBUG_DEBUG("Function call - function value type: %d", func_value.type); if (func_value.type != VAL_FUNCTION) { DEBUG_ERROR("Cannot call non-function value"); baba_yaga_value_destroy(&func_value); return baba_yaga_value_nil(); } /* Evaluate arguments */ int arg_count = baba_yaga_ast_get_function_call_arg_count(node); Value* args = malloc(arg_count * sizeof(Value)); if (args == NULL) { DEBUG_ERROR("Failed to allocate memory for function arguments"); baba_yaga_value_destroy(&func_value); return baba_yaga_value_nil(); } for (int i = 0; i < arg_count; i++) { void* arg_node = baba_yaga_ast_get_function_call_arg(node, i); args[i] = interpreter_evaluate_expression(arg_node, scope); } /* Call function */ DEBUG_DEBUG("Calling function with %d arguments", arg_count); Value result = baba_yaga_function_call(&func_value, args, arg_count, scope); DEBUG_DEBUG("Function call returned type: %d", result.type); /* Cleanup */ for (int i = 0; i < arg_count; i++) { baba_yaga_value_destroy(&args[i]); } free(args); baba_yaga_value_destroy(&func_value); return result; } case NODE_BINARY_OP: { void* left_node = baba_yaga_ast_get_binary_op_left(node); void* right_node = baba_yaga_ast_get_binary_op_right(node); const char* operator = baba_yaga_ast_get_binary_op_operator(node); if (left_node == NULL || right_node == NULL || operator == NULL) { DEBUG_ERROR("Invalid binary operation node"); return baba_yaga_value_nil(); } DEBUG_DEBUG("Binary operator: %s", operator); Value left = interpreter_evaluate_expression(left_node, scope); Value right = interpreter_evaluate_expression(right_node, scope); /* Create function call for the operator */ Value func_value = scope_get(scope, operator); DEBUG_DEBUG("Function lookup for '%s': type %d", operator, func_value.type); if (func_value.type != VAL_FUNCTION) { DEBUG_ERROR("Unknown operator: %s", operator); baba_yaga_value_destroy(&left); baba_yaga_value_destroy(&right); return baba_yaga_value_nil(); } Value args[2] = {left, right}; Value result = baba_yaga_function_call(&func_value, args, 2, scope); baba_yaga_value_destroy(&left); baba_yaga_value_destroy(&right); baba_yaga_value_destroy(&func_value); return result; } case NODE_UNARY_OP: { void* operand_node = baba_yaga_ast_get_unary_op_operand(node); const char* operator = baba_yaga_ast_get_unary_op_operator(node); if (operand_node == NULL || operator == NULL) { DEBUG_ERROR("Invalid unary operation node"); return baba_yaga_value_nil(); } Value operand = interpreter_evaluate_expression(operand_node, scope); /* Create function call for the operator */ Value func_value = scope_get(scope, operator); if (func_value.type != VAL_FUNCTION) { DEBUG_ERROR("Unknown operator: %s", operator); baba_yaga_value_destroy(&operand); return baba_yaga_value_nil(); } Value args[1] = {operand}; Value result = baba_yaga_function_call(&func_value, args, 1, scope); baba_yaga_value_destroy(&operand); baba_yaga_value_destroy(&func_value); return result; } case NODE_FUNCTION_DEF: { const char* name = baba_yaga_ast_get_function_def_name(node); int param_count = baba_yaga_ast_get_function_def_param_count(node); void* body_node = baba_yaga_ast_get_function_def_body(node); if (name == NULL || body_node == NULL) { DEBUG_ERROR("Invalid function definition node"); return baba_yaga_value_nil(); } /* Create user-defined function value */ FunctionValue* func_value = malloc(sizeof(FunctionValue)); if (func_value == NULL) { DEBUG_ERROR("Failed to allocate memory for function"); return baba_yaga_value_nil(); } /* Initialize function value */ func_value->name = strdup(name); func_value->type = FUNC_USER; func_value->param_count = param_count; func_value->required_params = param_count; func_value->ref_count = 1; func_value->closure_scope = NULL; /* TODO: Implement closures */ /* Allocate and copy parameters */ func_value->params = malloc(param_count * sizeof(FunctionParam)); if (func_value->params == NULL) { free(func_value->name); free(func_value); DEBUG_ERROR("Failed to allocate memory for function parameters"); return baba_yaga_value_nil(); } for (int i = 0; i < param_count; i++) { void* param_node = baba_yaga_ast_get_function_def_param(node, i); if (param_node != NULL && baba_yaga_ast_get_type(param_node) == NODE_IDENTIFIER) { const char* param_name = baba_yaga_ast_get_identifier(param_node); func_value->params[i].name = strdup(param_name); func_value->params[i].is_optional = false; } else { func_value->params[i].name = NULL; func_value->params[i].is_optional = false; } } /* Store function body */ func_value->body.user_body.ast_node = body_node; func_value->body.user_body.source = NULL; /* TODO: Store source for debugging */ /* Create function value */ Value func_val; func_val.type = VAL_FUNCTION; func_val.data.function = func_value; /* Define in current scope */ scope_define(scope, name, func_val, false); return func_val; } case NODE_VARIABLE_DECL: { const char* name = baba_yaga_ast_get_variable_decl_name(node); void* value_node = baba_yaga_ast_get_variable_decl_value(node); if (name == NULL || value_node == NULL) { DEBUG_ERROR("Invalid variable declaration node"); return baba_yaga_value_nil(); } Value value = interpreter_evaluate_expression(value_node, scope); DEBUG_DEBUG("Variable declaration: evaluating '%s' = value with type %d", name, value.type); scope_define(scope, name, value, false); return value; } case NODE_SEQUENCE: { int statement_count = baba_yaga_ast_get_sequence_statement_count(node); DEBUG_DEBUG("Executing sequence with %d statements", statement_count); Value result = baba_yaga_value_nil(); /* Execute all statements in sequence */ for (int i = 0; i < statement_count; i++) { void* statement_node = baba_yaga_ast_get_sequence_statement(node, i); if (statement_node == NULL) { DEBUG_ERROR("Invalid statement node at index %d", i); continue; } /* Destroy previous result before evaluating next statement */ baba_yaga_value_destroy(&result); /* Evaluate statement */ result = interpreter_evaluate_expression(statement_node, scope); DEBUG_DEBUG("Statement %d result type: %d", i, result.type); } return result; /* Return result of last statement */ } case NODE_WHEN_EXPR: { DEBUG_DEBUG("Evaluating NODE_WHEN_EXPR"); /* Evaluate the test expression */ void* test_node = baba_yaga_ast_get_when_expr_test(node); Value test_value = interpreter_evaluate_expression(test_node, scope); /* Get patterns */ int pattern_count = baba_yaga_ast_get_when_expr_pattern_count(node); /* Try each pattern in order */ for (int i = 0; i < pattern_count; i++) { void* pattern_node = baba_yaga_ast_get_when_expr_pattern(node, i); if (pattern_node == NULL) { continue; } /* Evaluate pattern test */ void* pattern_test_node = baba_yaga_ast_get_when_pattern_test(pattern_node); Value pattern_test_value = interpreter_evaluate_expression(pattern_test_node, scope); /* Check if pattern matches */ bool matches = false; if (pattern_test_value.type == VAL_NUMBER && test_value.type == VAL_NUMBER) { matches = (pattern_test_value.data.number == test_value.data.number); } else if (pattern_test_value.type == VAL_STRING && test_value.type == VAL_STRING) { matches = (strcmp(pattern_test_value.data.string, test_value.data.string) == 0); } else if (pattern_test_value.type == VAL_BOOLEAN && test_value.type == VAL_BOOLEAN) { matches = (pattern_test_value.data.boolean == test_value.data.boolean); } else if (pattern_test_value.type == VAL_STRING && strcmp(pattern_test_value.data.string, "_") == 0) { /* Wildcard pattern always matches */ matches = true; } else if (pattern_test_value.type == VAL_NIL && test_value.type == VAL_NIL) { /* Both are nil - match */ matches = true; } else if (pattern_test_value.type == VAL_TABLE && test_value.type == VAL_TABLE) { /* Table pattern matching: check if all pattern properties exist and match */ matches = true; /* Get all keys from the pattern table */ char* pattern_keys[100]; /* Assume max 100 keys */ size_t pattern_key_count = baba_yaga_table_get_keys(&pattern_test_value, pattern_keys, 100); /* Check each property in the pattern */ for (size_t i = 0; i < pattern_key_count; i++) { char* pattern_key = pattern_keys[i]; /* Check if this property exists in the test value */ if (!baba_yaga_table_has_key(&test_value, pattern_key)) { /* Property doesn't exist in test value */ matches = false; break; } /* Get pattern property value */ Value pattern_property = baba_yaga_table_get(&pattern_test_value, pattern_key); /* Get test property value */ Value test_property = baba_yaga_table_get(&test_value, pattern_key); /* Check if property values match */ bool property_matches = false; if (pattern_property.type == test_property.type) { switch (pattern_property.type) { case VAL_NUMBER: property_matches = (pattern_property.data.number == test_property.data.number); break; case VAL_STRING: property_matches = (strcmp(pattern_property.data.string, test_property.data.string) == 0); break; case VAL_BOOLEAN: property_matches = (pattern_property.data.boolean == test_property.data.boolean); break; default: property_matches = false; break; } } if (!property_matches) { matches = false; break; } } } baba_yaga_value_destroy(&pattern_test_value); if (matches) { /* Pattern matches, evaluate result */ void* result_node = baba_yaga_ast_get_when_pattern_result(pattern_node); Value result = interpreter_evaluate_expression(result_node, scope); baba_yaga_value_destroy(&test_value); return result; } } /* No pattern matched */ baba_yaga_value_destroy(&test_value); DEBUG_ERROR("No matching pattern in when expression"); return baba_yaga_value_nil(); } case NODE_TABLE: { DEBUG_DEBUG("Evaluating NODE_TABLE"); /* Evaluate table literal */ int element_count = baba_yaga_ast_get_table_element_count(node); DEBUG_DEBUG("Evaluating table with %d elements", element_count); /* Create a new table value */ Value table = baba_yaga_value_table(); /* Evaluate each element and add to table */ for (int i = 0; i < element_count; i++) { void* element_node = baba_yaga_ast_get_table_element(node, i); if (element_node == NULL) { DEBUG_ERROR("Table element %d is NULL", i); continue; } /* Check if this is a table_entry function call (key-value pair) */ NodeType element_type = baba_yaga_ast_get_type(element_node); if (element_type == NODE_FUNCTION_CALL) { /* Get function name */ void* func_node = baba_yaga_ast_get_function_call_func(element_node); if (func_node != NULL && baba_yaga_ast_get_type(func_node) == NODE_IDENTIFIER) { const char* func_name = baba_yaga_ast_get_identifier(func_node); if (func_name && strcmp(func_name, "table_entry") == 0) { /* This is a key-value pair */ int arg_count = baba_yaga_ast_get_function_call_arg_count(element_node); if (arg_count == 2) { /* Get key and value */ void* key_node = baba_yaga_ast_get_function_call_arg(element_node, 0); void* value_node = baba_yaga_ast_get_function_call_arg(element_node, 1); if (key_node != NULL && value_node != NULL) { Value key_value = interpreter_evaluate_expression(key_node, scope); Value element_value = interpreter_evaluate_expression(value_node, scope); /* Extract key string */ char* key_str = NULL; if (key_value.type == VAL_STRING) { key_str = strdup(key_value.data.string); } else if (key_value.type == VAL_NUMBER) { char num_str[32]; snprintf(num_str, sizeof(num_str), "%g", key_value.data.number); key_str = strdup(num_str); } else { key_str = strdup("unknown"); } DEBUG_DEBUG("Setting table key '%s' to element %d", key_str, i); table = baba_yaga_table_set(&table, key_str, &element_value); free(key_str); baba_yaga_value_destroy(&key_value); baba_yaga_value_destroy(&element_value); continue; } } } } } /* Fallback to array-like indexing (1-based) */ Value element_value = interpreter_evaluate_expression(element_node, scope); DEBUG_DEBUG("Table element %d evaluated to type %d", i, element_value.type); char key_str[32]; snprintf(key_str, sizeof(key_str), "%d", i + 1); Value key = baba_yaga_value_string(key_str); DEBUG_DEBUG("Setting table key '%s' to element %d", key_str, i); table = baba_yaga_table_set(&table, key.data.string, &element_value); baba_yaga_value_destroy(&key); baba_yaga_value_destroy(&element_value); } DEBUG_DEBUG("Table evaluation complete, final size: %zu", baba_yaga_table_size(&table)); return table; } case NODE_TABLE_ACCESS: { /* Evaluate table access: table.property or table[key] */ void* object_node = baba_yaga_ast_get_table_access_object(node); void* key_node = baba_yaga_ast_get_table_access_key(node); if (object_node == NULL || key_node == NULL) { DEBUG_ERROR("Invalid table access node"); return baba_yaga_value_nil(); } /* Evaluate the object (table) */ Value object = interpreter_evaluate_expression(object_node, scope); DEBUG_DEBUG("Table access - object type: %d", object.type); if (object.type != VAL_TABLE) { DEBUG_ERROR("Cannot access property of non-table value"); baba_yaga_value_destroy(&object); return baba_yaga_value_nil(); } /* Evaluate the key */ Value key = interpreter_evaluate_expression(key_node, scope); DEBUG_DEBUG("Table access - key type: %d", key.type); if (key.type != VAL_STRING && key.type != VAL_NUMBER) { DEBUG_ERROR("Table key must be string or number"); baba_yaga_value_destroy(&object); baba_yaga_value_destroy(&key); return baba_yaga_value_nil(); } /* Convert key to string for table lookup */ char* key_str; if (key.type == VAL_NUMBER) { key_str = malloc(32); if (key_str == NULL) { baba_yaga_value_destroy(&object); baba_yaga_value_destroy(&key); return baba_yaga_value_nil(); } snprintf(key_str, 32, "%g", key.data.number); } else { key_str = strdup(key.data.string); } DEBUG_DEBUG("Table access - looking up key: '%s'", key_str); /* Get the value from the table */ Value result = baba_yaga_table_get(&object, key_str); DEBUG_DEBUG("Table access - result type: %d", result.type); /* Cleanup */ free(key_str); baba_yaga_value_destroy(&object); baba_yaga_value_destroy(&key); return result; } default: DEBUG_ERROR("Unsupported expression type: %d", node_type); return baba_yaga_value_nil(); } } /** * @brief Evaluate a statement node * * @param node AST node to evaluate * @param scope Current scope * @return Result value */ __attribute__((unused)) static Value interpreter_evaluate_statement(void* node, Scope* scope) { if (node == NULL) { return baba_yaga_value_nil(); } NodeType node_type = baba_yaga_ast_get_type(node); DEBUG_TRACE("Evaluating statement: type %d", node_type); switch (node_type) { case NODE_VARIABLE_DECL: case NODE_FUNCTION_DEF: return interpreter_evaluate_expression(node, scope); default: DEBUG_ERROR("Unsupported statement type: %d", node_type); return baba_yaga_value_nil(); } } /* ============================================================================ * Error Handling Functions * ============================================================================ */ BabaYagaError* baba_yaga_get_error(const Interpreter* interp) { if (interp == NULL) { return NULL; } return interp->last_error; } void baba_yaga_error_destroy(BabaYagaError* error) { if (error == NULL) { return; } if (error->message != NULL) { free(error->message); } if (error->source_file != NULL) { free(error->source_file); } free(error); }