diff --git a/include/util.h b/include/util.h index 92f04bb..e99f3ff 100644 --- a/include/util.h +++ b/include/util.h @@ -103,6 +103,17 @@ libab_result libab_create_value_ref(libab* ab, libab_ref* into, */ libab_result libab_create_value_raw(libab* ab, libab_ref* into, void* data, libab_ref* type); +/** + * Overloads a function of the given name. + * @param table the table to insert the function into. + * @param name the name of the function. + * @param function the function to register. + * @return the result of the overload. + */ +libab_result libab_overload_function(libab* ab, + libab_table* table, + const char* name, + libab_ref* function); /** * Allocates a function that uses internal code to run. * @param into the reference into which to store the new function. diff --git a/src/interpreter.c b/src/interpreter.c index 9f5d121..0c4a6cc 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -1224,7 +1224,7 @@ libab_result _interpreter_run(struct interpreter_state* state, libab_tree* tree, _interpreter_create_function_value(state, tree, scope, &function); if(result == LIBAB_SUCCESS) { - result = libab_put_table_value(libab_ref_get(scope), + result = libab_overload_function(state->ab, libab_ref_get(scope), tree->string_value, &function); if(result != LIBAB_SUCCESS) { libab_ref_free(&function); diff --git a/src/libabacus.c b/src/libabacus.c index 9d76eec..32d475e 100644 --- a/src/libabacus.c +++ b/src/libabacus.c @@ -161,92 +161,16 @@ libab_result _create_value_function_internal(libab* ab, return result; } -libab_result _create_value_function_list(libab* ab, libab_ref* into, libab_ref* type) { - libab_ref list_ref; - libab_result result = libab_create_function_list(ab, &list_ref, type); - libab_ref_null(into); - if (result == LIBAB_SUCCESS) { - libab_ref_free(into); - result = libab_create_value_ref(ab, into, &list_ref, type); - } - libab_ref_free(&list_ref); - return result; -} - -libab_result _libab_register_function_existing(libab* ab, - libab_table_entry* entry, - libab_ref* function_val) { - libab_value* old_value; - libab_parsetype* old_type; - libab_result result = LIBAB_SUCCESS; - - old_value = libab_ref_get(&entry->data_u.value); - old_type = libab_ref_get(&old_value->type); - - if (old_type->data_u.base == &_basetype_function_list) { - libab_function_list* list = libab_ref_get(&old_value->data); - result = libab_function_list_insert(list, function_val); - } else if (old_type->data_u.base == &_basetype_function) { - libab_ref new_list; - result = - _create_value_function_list(ab, &new_list, &ab->type_function_list); - if (result == LIBAB_SUCCESS) { - libab_function_list* list = - libab_ref_get(&((libab_value*)libab_ref_get(&new_list))->data); - result = libab_function_list_insert(list, &entry->data_u.value); - if (result == LIBAB_SUCCESS) { - result = libab_function_list_insert(list, function_val); - } - } - if (result == LIBAB_SUCCESS) { - libab_ref_swap(&entry->data_u.value, &new_list); - } - libab_ref_free(&new_list); - } else { - libab_ref_swap(&entry->data_u.value, function_val); - } - - return result; -} - -libab_result _libab_register_function_new(libab* ab, const char* name, - libab_ref* function_val) { - libab_result result = LIBAB_SUCCESS; - libab_table_entry* entry; - if ((entry = malloc(sizeof(*entry)))) { - entry->variant = ENTRY_VALUE; - libab_ref_copy(function_val, &entry->data_u.value); - result = libab_table_put(libab_ref_get(&ab->table), name, entry); - - if (result != LIBAB_SUCCESS) { - libab_table_entry_free(entry); - free(entry); - } - } else { - result = LIBAB_MALLOC; - } - - return result; -} - libab_result libab_register_function(libab* ab, const char* name, libab_ref* type, libab_function_ptr func) { - libab_table_entry* existing_entry; libab_ref function_value; libab_result result = _create_value_function_internal(ab, &function_value, type, func, &ab->table); if (result == LIBAB_SUCCESS) { - existing_entry = libab_table_search_filter( - libab_ref_get(&ab->table), name, NULL, libab_table_compare_value); - if (existing_entry) { - result = _libab_register_function_existing(ab, existing_entry, - &function_value); - } else { - result = _libab_register_function_new(ab, name, &function_value); - } - libab_ref_free(&function_value); + libab_overload_function(ab, libab_ref_get(&ab->table), name, &function_value); } + libab_ref_free(&function_value); return result; } diff --git a/src/util.c b/src/util.c index b82b6c0..7ea6671 100644 --- a/src/util.c +++ b/src/util.c @@ -290,6 +290,94 @@ libab_result libab_create_value_raw(libab* ab, libab_ref* into, return result; } +libab_result _create_value_function_list(libab* ab, libab_ref* into, libab_ref* type) { + libab_ref list_ref; + libab_result result = libab_create_function_list(ab, &list_ref, type); + libab_ref_null(into); + if (result == LIBAB_SUCCESS) { + libab_ref_free(into); + result = libab_create_value_ref(ab, into, &list_ref, type); + } + libab_ref_free(&list_ref); + return result; +} + + +libab_result _register_function_existing(libab* ab, + libab_table_entry* entry, + libab_ref* function_val) { + libab_value* old_value; + libab_parsetype* old_type; + libab_result result = LIBAB_SUCCESS; + + old_value = libab_ref_get(&entry->data_u.value); + old_type = libab_ref_get(&old_value->type); + + if (old_type->data_u.base == libab_get_basetype_function_list(ab)) { + libab_function_list* list = libab_ref_get(&old_value->data); + result = libab_function_list_insert(list, function_val); + } else if (old_type->data_u.base == libab_get_basetype_function(ab)) { + libab_ref new_list; + result = + _create_value_function_list(ab, &new_list, &ab->type_function_list); + if (result == LIBAB_SUCCESS) { + libab_function_list* list = + libab_ref_get(&((libab_value*)libab_ref_get(&new_list))->data); + result = libab_function_list_insert(list, &entry->data_u.value); + if (result == LIBAB_SUCCESS) { + result = libab_function_list_insert(list, function_val); + } + } + if (result == LIBAB_SUCCESS) { + libab_ref_swap(&entry->data_u.value, &new_list); + } + libab_ref_free(&new_list); + } else { + libab_ref_swap(&entry->data_u.value, function_val); + } + + return result; +} + +libab_result _register_function_new(libab* ab, const char* name, + libab_ref* function_val) { + libab_result result = LIBAB_SUCCESS; + libab_table_entry* entry; + if ((entry = malloc(sizeof(*entry)))) { + entry->variant = ENTRY_VALUE; + libab_ref_copy(function_val, &entry->data_u.value); + result = libab_table_put(libab_ref_get(&ab->table), name, entry); + + if (result != LIBAB_SUCCESS) { + libab_table_entry_free(entry); + free(entry); + } + } else { + result = LIBAB_MALLOC; + } + + return result; +} + + +libab_result libab_overload_function(libab* ab, + libab_table* table, + const char* name, + libab_ref* function) { + libab_result result = LIBAB_SUCCESS; + libab_table_entry* existing_entry = libab_table_search_filter( + table, name, NULL, libab_table_compare_value); + + if (existing_entry) { + result = _register_function_existing(ab, existing_entry, + function); + } else { + result = _register_function_new(ab, name, function); + } + + return result; +} + void _gc_visit_function_children(void* function, libab_visitor_function_ptr visitor, void* data) { size_t index = 0; libab_function* func = function;