Make overloading code a utility function and call from interpreter.
This fixes #10.
This commit is contained in:
parent
25dd70f040
commit
4425b27b52
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_overload_function(ab, libab_ref_get(&ab->table), name, &function_value);
|
||||
}
|
||||
libab_ref_free(&function_value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
88
src/util.c
88
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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user