From 1cd7f3f45a04b4de8a21d14f9581d6f702eb9adb Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 22 May 2018 17:45:32 -0700 Subject: [PATCH] Finish the draft implementation. --- include/custom.h | 7 ++- src/custom.c | 5 +- src/interpreter.c | 125 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 127 insertions(+), 10 deletions(-) diff --git a/include/custom.h b/include/custom.h index 3bab1c9..1894cdc 100644 --- a/include/custom.h +++ b/include/custom.h @@ -9,7 +9,7 @@ * A function pointer that is called * to execute a certain type of function. */ -typedef void (*libab_function_ptr)(); +typedef libab_result (*libab_function_ptr)(libab_ref_vec*, libab_ref*); /** * The variant of the operator that @@ -87,6 +87,11 @@ struct libab_function_s { * The behavior of this function. */ struct libab_behavior_s behavior; + /** + * The parameters given to this function + * if it was created via partial application. + */ + libab_ref_vec params; }; typedef enum libab_operator_variant_e libab_operator_variant; diff --git a/src/custom.c b/src/custom.c index 51463dd..52680e6 100644 --- a/src/custom.c +++ b/src/custom.c @@ -32,7 +32,9 @@ void libab_operator_free(libab_operator* op) { libab_behavior_free(&op->behavior); } -libab_result _function_init(libab_function* function) { return LIBAB_SUCCESS; } +libab_result _function_init(libab_function* function) { + return libab_ref_vec_init(&function->params); +} libab_result libab_function_init_internal(libab_function* function, libab_function_ptr fun) { libab_result result = _function_init(function); @@ -47,4 +49,5 @@ libab_result libab_function_init_tree(libab_function* function, } void libab_function_free(libab_function* fun) { libab_behavior_free(&fun->behavior); + libab_ref_vec_free(&fun->params); } diff --git a/src/interpreter.c b/src/interpreter.c index 5b41930..7eef3f2 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -42,6 +42,20 @@ libab_result _interpreter_create_num_val(struct interpreter_state* state, return result; } +int _interpreter_type_contains_placeholders(libab_ref* type) { + size_t index = 0; + int placeholder; + libab_ref temp_child; + libab_parsetype* parsetype = libab_ref_get(type); + placeholder = (parsetype->variant & LIBABACUS_TYPE_F_PLACE) != 0; + for(; index < parsetype->children.size && !placeholder; index++) { + libab_ref_vec_index(&parsetype->children, index, &temp_child); + placeholder |= _interpreter_type_contains_placeholders(&temp_child); + libab_ref_free(&temp_child); + } + return placeholder; +} + libab_result _interpreter_compare_types(libab_ref* left_type, libab_ref* right_type, libab_ref_trie* left_params, libab_ref_trie* right_params) { libab_result result = LIBAB_SUCCESS; @@ -61,15 +75,25 @@ libab_result _interpreter_compare_types(libab_ref* left_type, libab_ref* right_t libab_ref_trie_get(left_params, name, ¶m_type); left = libab_ref_get(¶m_type); libab_ref_free(¶m_type); - if(left == NULL) - result = libab_ref_trie_put(left_params, name, right_type); + if(left == NULL) { + if(!_interpreter_type_contains_placeholders(right_type)) { + result = libab_ref_trie_put(left_params, name, right_type); + } else { + result = LIBAB_AMBIGOUS_TYPE; + } + } } else if(right_placeholder) { const char* name = right->data_u.name; libab_ref_trie_get(right_params, name, ¶m_type); right = libab_ref_get(¶m_type); libab_ref_free(¶m_type); - if(right == NULL) - result = libab_ref_trie_put(right_params, name, left_type); + if(right == NULL) { + if(!_interpreter_type_contains_placeholders(left_type)) { + result = libab_ref_trie_put(right_params, name, left_type); + } else { + result = LIBAB_AMBIGOUS_TYPE; + } + } } if(left != NULL && right != NULL) { @@ -97,8 +121,67 @@ libab_result _interpreter_compare_types(libab_ref* left_type, libab_ref* right_t return result; } +void _free_parsetype(void* parsetype) { + libab_parsetype_free(parsetype); + free(parsetype); +} + +libab_result _interpreter_copy_resolved_type(libab_ref* type, libab_ref_trie* params, libab_ref* into) { + libab_result result = LIBAB_SUCCESS; + libab_parsetype* copy; + libab_parsetype* original; + + original = libab_ref_get(type); + if(original->variant & LIBABACUS_TYPE_F_PLACE) { + libab_ref_trie_get(params, original->data_u.name, into); + } else if((copy = malloc(sizeof(*copy)))) { + size_t index = 0; + copy->variant = original->variant; + copy->data_u.base = original->data_u.base; + if(copy->variant & LIBABACUS_TYPE_F_PARENT) { + libab_ref child_copy; + libab_ref temp_child; + result = libab_ref_vec_init(©->children); + for(; index < original->children.size && result == LIBAB_SUCCESS; index++) { + libab_ref_vec_index(&original->children, index, &temp_child); + result = _interpreter_copy_resolved_type(&temp_child, params, &child_copy); + if(result == LIBAB_SUCCESS) { + result = libab_ref_vec_insert(©->children, &child_copy); + } + + if(result != LIBAB_SUCCESS) { + libab_parsetype_free(copy); + } + + libab_ref_free(&child_copy); + libab_ref_free(&temp_child); + } + + if(result == LIBAB_SUCCESS) { + result = libab_ref_new(into, copy, _free_parsetype); + if(result != LIBAB_SUCCESS) { + _free_parsetype(copy); + } + } + } + } else { + result = LIBAB_MALLOC; + } + + if(result != LIBAB_SUCCESS) { + libab_ref_null(into); + } + + return result; +} + libab_result _interpreter_resolve_type_params(libab_ref* type, libab_ref_trie* params, libab_ref* into) { libab_result result = LIBAB_SUCCESS; + if(_interpreter_type_contains_placeholders(type)) { + result = _interpreter_copy_resolved_type(type, params, into); + } else { + libab_ref_copy(type, into); + } return result; } @@ -254,16 +337,41 @@ libab_result _interpreter_cast_params(libab_ref_vec* params, libab_ref_vec* new_ return result; } -libab_result _interpreter_perform_call(libab_function* to_call, libab_ref_vec* params, libab_ref* into) { +libab_result _interpreter_call_tree(libab_tree* tree, libab_ref_vec* params, libab_ref* into) { libab_result result = LIBAB_SUCCESS; return result; } +libab_result _interpreter_call_behavior(libab_behavior* behavior, libab_ref_vec* params, libab_ref* into) { + libab_result result = LIBAB_SUCCESS; + if(behavior->variant == BIMPL_INTERNAL) { + result = behavior->data_u.internal(params, into); + } else { + result = _interpreter_call_tree(behavior->data_u.tree, params, into); + } + return result; +} + +libab_result _interpreter_perform_call(libab_value* to_call, libab_ref_vec* params, libab_ref* into) { + libab_result result = LIBAB_SUCCESS; + libab_function* function; + libab_parsetype* function_type; + size_t new_params; + function = libab_ref_get(&to_call->data); + function_type = libab_ref_get(&to_call->type); + new_params = params->size - function->params.size; + if(function_type->children.size - new_params == 1) { + _interpreter_call_behavior(&function->behavior, params, into); + } + return result; +} + libab_result _interpreter_call_function_list(struct interpreter_state* state, - libab_function_list* list, libab_ref_vec* params) { + libab_function_list* list, libab_ref_vec* params, libab_ref* into) { libab_result result = LIBAB_SUCCESS; libab_ref_vec new_types; libab_ref to_call; + libab_ref_null(into); result = _interpreter_find_match(state, list, params, &new_types, &to_call, 0); if(result == LIBAB_SUCCESS) { @@ -280,12 +388,13 @@ libab_result _interpreter_call_function_list(struct interpreter_state* state, libab_ref_vec new_params; libab_function* function; function = libab_ref_get(&to_call); - /* result = libab_ref_vec_init_copy(&new_params, &function->params); */ + result = libab_ref_vec_init_copy(&new_params, &function->params); if(result == LIBAB_SUCCESS) { result = _interpreter_cast_params(params, &new_types, &new_params); if(result == LIBAB_SUCCESS) { - result = _interpreter_perform_call(function, &new_params, NULL); + libab_ref_free(into); + result = _interpreter_perform_call(libab_ref_get(&to_call), &new_params, into); } if(result != LIBAB_SUCCESS) {