diff options
Diffstat (limited to '055shape_shifting_container.cc')
-rw-r--r-- | 055shape_shifting_container.cc | 42 |
1 files changed, 40 insertions, 2 deletions
diff --git a/055shape_shifting_container.cc b/055shape_shifting_container.cc index 90f1f955..6083f904 100644 --- a/055shape_shifting_container.cc +++ b/055shape_shifting_container.cc @@ -353,12 +353,41 @@ void replace_type_ingredients(type_tree* element_type, const type_tree* callsite if (!callsite_type) return; // error but it's already been raised above if (!element_type) return; if (!element_type->atom) { + if (element_type->right == NULL && is_type_ingredient(element_type->left)) { + int type_ingredient_index = to_type_ingredient_index(element_type->left); + if (corresponding(callsite_type, type_ingredient_index, is_final_type_ingredient(type_ingredient_index, container_info))->right) { + // replacing type ingredient at end of list, and replacement is a non-degenerate compound type -- (a b) but not (a) + replace_type_ingredient_at(type_ingredient_index, element_type, callsite_type, container_info, location_for_error_messages); + return; + } + } replace_type_ingredients(element_type->left, callsite_type, container_info, location_for_error_messages); replace_type_ingredients(element_type->right, callsite_type, container_info, location_for_error_messages); return; } - if (element_type->value < START_TYPE_INGREDIENTS) return; - const int type_ingredient_index = element_type->value-START_TYPE_INGREDIENTS; + if (is_type_ingredient(element_type)) + replace_type_ingredient_at(to_type_ingredient_index(element_type), element_type, callsite_type, container_info, location_for_error_messages); +} + +const type_tree* corresponding(const type_tree* type, int index, bool final) { + for (const type_tree* curr = type; curr; curr = curr->right, --index) { + assert_for_now(!curr->atom); + if (index == 0) + return final ? curr : curr->left; + } + assert_for_now(false); +} + +bool is_type_ingredient(const type_tree* type) { + return type->atom && type->value >= START_TYPE_INGREDIENTS; +} + +int to_type_ingredient_index(const type_tree* type) { + assert(type->atom); + return type->value-START_TYPE_INGREDIENTS; +} + +void replace_type_ingredient_at(const int type_ingredient_index, type_tree* element_type, const type_tree* callsite_type, const type_info& container_info, const string& location_for_error_messages) { if (!has_nth_type(callsite_type, type_ingredient_index)) { raise << "illegal type " << names_to_string(callsite_type) << " seems to be missing a type ingredient or three" << location_for_error_messages << '\n' << end(); return; @@ -450,6 +479,15 @@ void test_replace_last_type_ingredient_with_multiple() { CHECK_EQ(to_string(element2), "{y: (\"address\" \"array\" \"character\")}"); } +void test_replace_last_type_ingredient_inside_compound() { + run("container foo:_a:_b [\n" + " {x: (bar _a (address _b))}\n" + "]\n"); + reagent callsite("f:foo:number:array:character"); + reagent element = element_type(callsite.type, 0); + CHECK_EQ(names_to_string_without_quotes(element.type), "(bar number (address array character))"); +} + void test_replace_middle_type_ingredient_with_multiple() { run("container foo:_a:_b:_c [\n" " x:_a\n" |