diff --git a/include/util.h b/include/util.h index 63c91d8..cf48fb2 100644 --- a/include/util.h +++ b/include/util.h @@ -55,8 +55,18 @@ libab_result libab_copy_string(char** destination, const char* source); * @param to_resolve the parsetype to resolve. * @param scope the scope to use for resolving the type info. */ -libab_result libab_resolve_parsetype(libab_parsetype* to_resolve, +libab_result libab_resolve_parsetype_inplace(libab_parsetype* to_resolve, libab_table* scope); +/** + * Resolves the given parsetype, looking through the scope to find + * all referenced base types, and creates a copy with these basetypes. + * @param to_resolve the parsetype to resolve. + * @param scope the scope to use for resolving the type info. + * @return the result of the operation. + */ +libab_result libab_resolve_parsetype_copy(libab_parsetype* to_resolve, + libab_table* scope, + libab_ref* into); /** * Creates a new type instance, and stores it into the given reference. * @param to_instantiate the basetype to instantiate. @@ -143,6 +153,13 @@ libab_result libab_create_function_list(libab_ref* into, libab_ref* type); */ libab_result libab_put_table_value(libab_table* table, const char* key, libab_ref* value); +/** + * Gets the basetype of a parsetype. + * @param type the parsetype to get the basetype of. + * @param scope the scope to use for searches. + * @return the basetype. + */ +libab_basetype* libab_get_basetype(libab_parsetype* type, libab_table* scope); /** * Returns the data stored in the given reference to a libab_value. * This is not the same as libab_ref_get: libab_ref_get will return directly diff --git a/src/interpreter.c b/src/interpreter.c index ff70d48..d754cb8 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -96,23 +96,6 @@ libab_parsetype* _interpreter_search_type_param_raw(libab_ref_trie* params, return to_return; } -libab_basetype* _interpreter_get_basetype(libab_parsetype* type, - libab_table* scope) { - libab_ref type_param; - libab_basetype* to_return; - if(type->variant & LIBABACUS_TYPE_F_RESOLVED) { - to_return = type->data_u.base; - } else { - to_return = libab_table_search_basetype(scope, type->data_u.name); - if(to_return == NULL) { - libab_table_search_type_param(scope, type->data_u.name, &type_param); - to_return = libab_ref_get(&type_param); - libab_ref_free(&type_param); - } - } - return to_return; -} - /** * Compares the two types, filling in any missing type parameters * in the respective type tries. @@ -162,14 +145,10 @@ libab_result _interpreter_compare_types(libab_ref* left_type, if (left != NULL && right != NULL) { size_t index = 0; - libab_basetype* base_left; - libab_basetype* base_right; libab_ref temp_left; libab_ref temp_right; - base_left = _interpreter_get_basetype(left, libab_ref_get(scope)); - base_right = _interpreter_get_basetype(right, libab_ref_get(scope)); - result = (base_left == base_right) + result = (left->data_u.base == right->data_u.base) ? LIBAB_SUCCESS : LIBAB_MISMATCHED_TYPE; if (result == LIBAB_SUCCESS && @@ -222,7 +201,7 @@ libab_result _interpreter_copy_resolved_type(libab_ref* type, } else if ((copy = malloc(sizeof(*copy)))) { size_t index = 0; copy->variant = original->variant; - copy->data_u.base = _interpreter_get_basetype(original, libab_ref_get(scope)); + copy->data_u.base = original->data_u.base; if (copy->variant & LIBABACUS_TYPE_F_PARENT) { libab_ref child_copy; libab_ref temp_child; @@ -1019,15 +998,30 @@ int _interpreter_compare_function_param( return data->variant == TREE_FUN_PARAM; } +libab_result _interpreter_resolve_and_insert_param( + libab_parsetype* type, libab_table* scope, libab_ref_vec* into) { + libab_result result = LIBAB_SUCCESS; + libab_ref copy; + result = libab_resolve_parsetype_copy(type, scope, ©); + if(result == LIBAB_SUCCESS) { + result = libab_ref_vec_insert(into, ©); + } + libab_ref_free(©); + return result; +} + int _interpreter_foreach_insert_function_param( void* data, va_list args) { libab_tree* tree = data; libab_ref_vec* into = va_arg(args, libab_ref_vec*); - return libab_ref_vec_insert(into, &tree->type); + libab_ref* scope = va_arg(args, libab_ref*); + return _interpreter_resolve_and_insert_param(libab_ref_get(&tree->type), + libab_ref_get(scope), + into); } libab_result _interpreter_create_function_type( - struct interpreter_state* state, libab_tree* tree, libab_parsetype** type) { + struct interpreter_state* state, libab_tree* tree, libab_ref* scope, libab_parsetype** type) { libab_result result = LIBAB_SUCCESS; libab_basetype* funciton_type = libab_get_basetype_function(state->ab); @@ -1041,9 +1035,10 @@ libab_result _interpreter_create_function_type( if(result == LIBAB_SUCCESS) { result = vec_foreach(&tree->children, NULL, _interpreter_compare_function_param, - _interpreter_foreach_insert_function_param, &(*type)->children); + _interpreter_foreach_insert_function_param, &(*type)->children, scope); if(result == LIBAB_SUCCESS) { - result = libab_ref_vec_insert(&(*type)->children, &tree->type); + result = _interpreter_resolve_and_insert_param(libab_ref_get(&tree->type), + libab_ref_get(scope), &(*type)->children); } if(result != LIBAB_SUCCESS) { libab_ref_vec_free(&(*type)->children); @@ -1059,9 +1054,9 @@ libab_result _interpreter_create_function_type( } libab_result _interpreter_wrap_function_type( - struct interpreter_state* state, libab_tree* tree, libab_ref* into) { + struct interpreter_state* state, libab_tree* tree, libab_ref* scope, libab_ref* into) { libab_parsetype* type; - libab_result result = _interpreter_create_function_type(state, tree, &type); + libab_result result = _interpreter_create_function_type(state, tree, scope, &type); if(result == LIBAB_SUCCESS) { result = libab_ref_new(into, type, free_parsetype); @@ -1085,7 +1080,7 @@ libab_result _interpreter_create_function_value( if(result == LIBAB_SUCCESS) { libab_ref_free(&type); - result = _interpreter_wrap_function_type(state, tree, &type); + result = _interpreter_wrap_function_type(state, tree, scope, &type); } if(result == LIBAB_SUCCESS) { diff --git a/src/libabacus.c b/src/libabacus.c index 1a948f7..5b67105 100644 --- a/src/libabacus.c +++ b/src/libabacus.c @@ -340,7 +340,7 @@ libab_result libab_create_type(libab* ab, libab_ref* into, const char* type) { result = libab_parser_parse_type(&ab->parser, &tokens, type, into); } if (result == LIBAB_SUCCESS) { - result = libab_resolve_parsetype(libab_ref_get(into), + result = libab_resolve_parsetype_inplace(libab_ref_get(into), libab_ref_get(&ab->table)); } ll_foreach(&tokens, NULL, compare_always, libab_lexer_foreach_match_free); diff --git a/src/util.c b/src/util.c index 5738e41..e383a52 100644 --- a/src/util.c +++ b/src/util.c @@ -45,7 +45,7 @@ libab_result _libab_check_parsetype(libab_parsetype* to_check) { libab_result result = LIBAB_SUCCESS; return result; } -libab_result libab_resolve_parsetype(libab_parsetype* to_resolve, +libab_result libab_resolve_parsetype_inplace(libab_parsetype* to_resolve, libab_table* scope) { libab_result result = LIBAB_SUCCESS; int resolve_name, check_parents; @@ -61,7 +61,7 @@ libab_result libab_resolve_parsetype(libab_parsetype* to_resolve, if (resolve_name && result == LIBAB_SUCCESS) { libab_basetype* basetype = - libab_table_search_basetype(scope, to_resolve->data_u.name); + libab_get_basetype(to_resolve, scope); if (basetype) { free(to_resolve->data_u.name); to_resolve->data_u.base = basetype; @@ -81,7 +81,7 @@ libab_result libab_resolve_parsetype(libab_parsetype* to_resolve, if (to_resolve->variant & LIBABACUS_TYPE_F_PARENT) { while (result == LIBAB_SUCCESS && index < to_resolve->children.size) { - result = libab_resolve_parsetype( + result = libab_resolve_parsetype_inplace( libab_ref_get(&to_resolve->children.data[index]), scope); index++; } @@ -90,14 +90,61 @@ libab_result libab_resolve_parsetype(libab_parsetype* to_resolve, return result; } -void _libab_free_parsetype(void* parsetype) { - libab_parsetype_free(parsetype); - free(parsetype); -} +libab_result libab_resolve_parsetype_copy(libab_parsetype* to_resolve, + libab_table* scope, + libab_ref* into) { + libab_result result = LIBAB_SUCCESS; + libab_parsetype* parsetype; + if((parsetype = malloc(sizeof(*parsetype)))) { + parsetype->variant = to_resolve->variant | LIBABACUS_TYPE_F_RESOLVED; + } else { + result = LIBAB_MALLOC; + } -void _libab_parsetype_free(void* parsetype) { - libab_parsetype_free(parsetype); - free(parsetype); + if(result == LIBAB_SUCCESS) { + libab_basetype* parent_basetype = libab_get_basetype(to_resolve, scope); + if(parent_basetype) { + parsetype->data_u.base = parent_basetype; + } else { + result = LIBAB_UNKNOWN_TYPE; + } + } + + + if(result == LIBAB_SUCCESS && (to_resolve->variant & LIBABACUS_TYPE_F_PARENT)) { + result = libab_ref_vec_init(&parsetype->children); + } + + if(result == LIBAB_SUCCESS && (to_resolve->variant & LIBABACUS_TYPE_F_PARENT)) { + size_t i; + libab_ref temp; + libab_ref new_type; + for(i = 0; i < to_resolve->children.size && result == LIBAB_SUCCESS; i++) { + libab_ref_vec_index(&to_resolve->children, i, &temp); + result = libab_resolve_parsetype_copy(libab_ref_get(&temp), scope, &new_type); + if(result == LIBAB_SUCCESS) { + libab_ref_vec_insert(&parsetype->children, &new_type); + } + libab_ref_free(&new_type); + libab_ref_free(&temp); + } + + if(result != LIBAB_SUCCESS) { + libab_ref_vec_free(&parsetype->children); + } + } + + if(result == LIBAB_SUCCESS) { + result = libab_ref_new(into, parsetype, free_parsetype); + if(result != LIBAB_SUCCESS) libab_parsetype_free(parsetype); + } + + if(result != LIBAB_SUCCESS) { + free(parsetype); + libab_ref_null(into); + } + + return result; } libab_result libab_instantiate_basetype(libab_basetype* to_instantiate, @@ -115,7 +162,7 @@ libab_result libab_instantiate_basetype(libab_basetype* to_instantiate, } if (result == LIBAB_SUCCESS) { - result = libab_ref_new(into, parsetype, _libab_parsetype_free); + result = libab_ref_new(into, parsetype, free_parsetype); if (result != LIBAB_SUCCESS) { libab_parsetype_free(parsetype); } @@ -332,6 +379,22 @@ libab_result libab_put_table_value(libab_table* table, const char* key, return result; } +libab_basetype* libab_get_basetype(libab_parsetype* type, libab_table* scope) { + libab_ref type_param; + libab_basetype* to_return; + if(type->variant & LIBABACUS_TYPE_F_RESOLVED) { + to_return = type->data_u.base; + } else { + to_return = libab_table_search_basetype(scope, type->data_u.name); + if(to_return == NULL) { + libab_table_search_type_param(scope, type->data_u.name, &type_param); + to_return = libab_ref_get(&type_param); + libab_ref_free(&type_param); + } + } + return to_return; +} + void* libab_unwrap_value(libab_ref* ref) { libab_value* value = libab_ref_get(ref); return libab_ref_get(&value->data);