Make overloading code a utility function and call from interpreter.

This fixes #10.
This commit is contained in:
Danila Fedorin 2018-09-13 16:08:49 -07:00
parent 25dd70f040
commit 4425b27b52
4 changed files with 102 additions and 79 deletions

View File

@ -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, libab_result libab_create_value_raw(libab* ab, libab_ref* into,
void* data, libab_ref* type); 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. * Allocates a function that uses internal code to run.
* @param into the reference into which to store the new function. * @param into the reference into which to store the new function.

View File

@ -1224,7 +1224,7 @@ libab_result _interpreter_run(struct interpreter_state* state, libab_tree* tree,
_interpreter_create_function_value(state, tree, scope, &function); _interpreter_create_function_value(state, tree, scope, &function);
if(result == LIBAB_SUCCESS) { 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); tree->string_value, &function);
if(result != LIBAB_SUCCESS) { if(result != LIBAB_SUCCESS) {
libab_ref_free(&function); libab_ref_free(&function);

View File

@ -161,92 +161,16 @@ libab_result _create_value_function_internal(libab* ab,
return result; 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_result libab_register_function(libab* ab, const char* name,
libab_ref* type, libab_function_ptr func) { libab_ref* type, libab_function_ptr func) {
libab_table_entry* existing_entry;
libab_ref function_value; libab_ref function_value;
libab_result result = libab_result result =
_create_value_function_internal(ab, &function_value, type, func, &ab->table); _create_value_function_internal(ab, &function_value, type, func, &ab->table);
if (result == LIBAB_SUCCESS) { if (result == LIBAB_SUCCESS) {
existing_entry = libab_table_search_filter( libab_overload_function(ab, libab_ref_get(&ab->table), name, &function_value);
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_ref_free(&function_value);
return result; return result;
} }

View File

@ -290,6 +290,94 @@ libab_result libab_create_value_raw(libab* ab, libab_ref* into,
return result; 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) { void _gc_visit_function_children(void* function, libab_visitor_function_ptr visitor, void* data) {
size_t index = 0; size_t index = 0;
libab_function* func = function; libab_function* func = function;