diff options
Diffstat (limited to 'js/scripting-lang/baba-yaga-c/src/interpreter.c')
-rw-r--r-- | js/scripting-lang/baba-yaga-c/src/interpreter.c | 287 |
1 files changed, 280 insertions, 7 deletions
diff --git a/js/scripting-lang/baba-yaga-c/src/interpreter.c b/js/scripting-lang/baba-yaga-c/src/interpreter.c index adc3c84..4b53e7d 100644 --- a/js/scripting-lang/baba-yaga-c/src/interpreter.c +++ b/js/scripting-lang/baba-yaga-c/src/interpreter.c @@ -48,6 +48,9 @@ typedef struct { 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 * ============================================================================ */ @@ -119,6 +122,19 @@ static void register_stdlib(Scope* scope) { Value greater_equal_func = baba_yaga_value_function("greater_equal", stdlib_greater_equal, 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, 2, 2); + scope_define(scope, "greaterThan", greater_than_func, true); + + Value less_than_func = baba_yaga_value_function("lessThan", stdlib_less, 2, 2); + scope_define(scope, "lessThan", less_than_func, true); + + Value greater_equal_than_func = baba_yaga_value_function("greaterEqual", stdlib_greater_equal, 2, 2); + scope_define(scope, "greaterEqual", greater_equal_than_func, true); + + Value less_equal_than_func = baba_yaga_value_function("lessEqual", stdlib_less_equal, 2, 2); + scope_define(scope, "lessEqual", less_equal_than_func, true); + /* Logical functions */ Value and_func = baba_yaga_value_function("and", stdlib_and, 2, 2); scope_define(scope, "and", and_func, true); @@ -146,6 +162,12 @@ static void register_stdlib(Scope* scope) { Value assert_func = baba_yaga_value_function("assert", stdlib_assert, 1, 1); scope_define(scope, "assert", assert_func, true); + Value emit_func = baba_yaga_value_function("emit", stdlib_emit, 1, 1); + scope_define(scope, "emit", emit_func, true); + + Value listen_func = baba_yaga_value_function("listen", stdlib_listen, 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); @@ -156,7 +178,63 @@ static void register_stdlib(Scope* scope) { Value reduce_func = baba_yaga_value_function("reduce", stdlib_reduce, 3, 3); scope_define(scope, "reduce", reduce_func, true); - DEBUG_INFO("Registered %d standard library functions", 20); + /* Advanced combinators */ + Value each_func = baba_yaga_value_function("each", stdlib_each, 3, 2); + scope_define(scope, "each", each_func, true); + + Value flip_func = baba_yaga_value_function("flip", stdlib_flip, 3, 1); + scope_define(scope, "flip", flip_func, true); + + Value constant_func = baba_yaga_value_function("constant", stdlib_constant, 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, 2, 2); + scope_define(scope, "t.map", t_map_func, true); + + Value t_filter_func = baba_yaga_value_function("t.filter", stdlib_t_filter, 2, 2); + scope_define(scope, "t.filter", t_filter_func, true); + + Value t_reduce_func = baba_yaga_value_function("t.reduce", stdlib_t_reduce, 3, 3); + scope_define(scope, "t.reduce", t_reduce_func, true); + + Value t_set_func = baba_yaga_value_function("t.set", stdlib_t_set, 3, 3); + scope_define(scope, "t.set", t_set_func, true); + + Value t_delete_func = baba_yaga_value_function("t.delete", stdlib_t_delete, 2, 2); + scope_define(scope, "t.delete", t_delete_func, true); + + Value t_merge_func = baba_yaga_value_function("t.merge", stdlib_t_merge, 2, 2); + scope_define(scope, "t.merge", t_merge_func, true); + + Value t_length_func = baba_yaga_value_function("t.length", stdlib_t_length, 1, 1); + scope_define(scope, "t.length", t_length_func, true); + + Value t_has_func = baba_yaga_value_function("t.has", stdlib_t_has, 2, 2); + scope_define(scope, "t.has", t_has_func, true); + + Value t_get_func = baba_yaga_value_function("t.get", stdlib_t_get, 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, 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); } /* ============================================================================ @@ -328,11 +406,14 @@ Value interpreter_evaluate_expression(void* node, Scope* scope) { } NodeType node_type = baba_yaga_ast_get_type(node); - DEBUG_TRACE("Evaluating expression: type %d", node_type); + DEBUG_DEBUG("Evaluating expression: type %d", node_type); switch (node_type) { - case NODE_LITERAL: - return baba_yaga_ast_get_literal(node); + 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); @@ -366,6 +447,7 @@ Value interpreter_evaluate_expression(void* node, Scope* scope) { } 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); @@ -394,7 +476,7 @@ Value interpreter_evaluate_expression(void* node, Scope* scope) { /* Call function */ DEBUG_DEBUG("Calling function with %d arguments", arg_count); - Value result = baba_yaga_function_call(&func_value, args, arg_count); + Value result = baba_yaga_function_call(&func_value, args, arg_count, scope); DEBUG_DEBUG("Function call returned type: %d", result.type); /* Cleanup */ @@ -433,7 +515,7 @@ Value interpreter_evaluate_expression(void* node, Scope* scope) { } Value args[2] = {left, right}; - Value result = baba_yaga_function_call(&func_value, args, 2); + Value result = baba_yaga_function_call(&func_value, args, 2, scope); baba_yaga_value_destroy(&left); baba_yaga_value_destroy(&right); @@ -462,7 +544,7 @@ Value interpreter_evaluate_expression(void* node, Scope* scope) { } Value args[1] = {operand}; - Value result = baba_yaga_function_call(&func_value, args, 1); + Value result = baba_yaga_function_call(&func_value, args, 1, scope); baba_yaga_value_destroy(&operand); baba_yaga_value_destroy(&func_value); @@ -540,7 +622,9 @@ Value interpreter_evaluate_expression(void* node, Scope* scope) { 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; } @@ -571,6 +655,7 @@ Value interpreter_evaluate_expression(void* node, Scope* scope) { } 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); @@ -601,6 +686,57 @@ Value interpreter_evaluate_expression(void* node, Scope* scope) { 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); @@ -620,6 +756,143 @@ Value interpreter_evaluate_expression(void* node, Scope* scope) { 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(); |