diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2016-02-18 01:19:36 -0800 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2016-02-18 01:21:29 -0800 |
commit | 07ca569193dabb30d1d7da1ec0adc2c9ea061fb6 (patch) | |
tree | 05a9cb129d272213696fefa616de13674ac9fe09 | |
parent | 00472b898df4a7c1d1f4b5b9278d9274fcacd274 (diff) | |
download | mu-07ca569193dabb30d1d7da1ec0adc2c9ea061fb6.tar.gz |
2670 - improvements to generics
Eliminated a few holes, gained more clarity on the shape of others. Maybe I was sleep-deprived, but this was really hard until I wrote a few unit tests directly on replace_type_ingredient. Still one flaw remaining: the type-checker isn't smart enough to handle 'merge' for all the new cases. Tests pass since we don't use those features outside C++ tests yet.
-rw-r--r-- | 030container.cc | 2 | ||||
-rw-r--r-- | 058shape_shifting_container.cc | 155 |
2 files changed, 146 insertions, 11 deletions
diff --git a/030container.cc b/030container.cc index cd9d3255..a7ae2984 100644 --- a/030container.cc +++ b/030container.cc @@ -808,6 +808,8 @@ void check_merge_call(const vector<reagent>& ingredients, const reagent& product default: { if (!types_coercible(container, ingredients.at(ingredient_index))) { raise_error << maybe(caller.name) << "incorrect type of ingredient " << ingredient_index << " in '" << inst.to_string() << "'\n" << end(); + cerr << " expected " << debug_string(container) << '\n'; + cerr << " got " << debug_string(ingredients.at(ingredient_index)) << '\n'; return; } ++ingredient_index; diff --git a/058shape_shifting_container.cc b/058shape_shifting_container.cc index 476468b7..8789e781 100644 --- a/058shape_shifting_container.cc +++ b/058shape_shifting_container.cc @@ -1,9 +1,7 @@ -//:: Container definitions can contain type parameters. +//:: Container definitions can contain 'type ingredients' //: -//: Extremely hacky initial implementation. We still don't support the full -//: complexity of type trees inside container definitions. So for example you -//: can't have a container element with this type: -//: (map (array address character) (list number)) +//: Incomplete implementation; see the pending test below. There may be +//: others. :(scenario size_of_shape_shifting_container) container foo:_t [ @@ -20,6 +18,41 @@ recipe main [ +mem: storing 15 in location 4 +mem: storing 16 in location 5 +:(scenario size_of_shape_shifting_container_2) +# multiple type ingredients +container foo:_a:_b [ + x:_a + y:_b +] +recipe main [ + 1:foo:number:boolean <- merge 34, 1/true +] + +:(scenario size_of_shape_shifting_container_3) +container foo:_a:_b [ + x:_a + y:_b +] +recipe main [ + 1:address:shared:array:character <- new [abc] + # compound types for type ingredients + {2: (foo number (address shared array character))} <- merge 34/x, 1:address:shared:array:character/y +] + +:(scenario size_of_shape_shifting_container_4) +container foo:_a:_b [ + x:_a + y:_b +] +container bar:_a:_b [ + # dilated element + {data: (foo _a (address shared _b))} +] +recipe main [ + 1:address:shared:array:character <- new [abc] + 2:bar:number:array:character <- merge 34/x, 1:address:shared:array:character/y +] + :(before "End Globals") // We'll use large type ordinals to mean "the following type of the variable". const int START_TYPE_INGREDIENTS = 2000; @@ -129,8 +162,8 @@ type_tree* type_ingredient(const type_tree* element_template, const type_tree* r if (!curr) return NULL; } assert(curr); - assert(!curr->left); // unimplemented - if (!contains_key(Type, curr->value)) return NULL; + if (curr->left) curr = curr->left; + assert(curr->value > 0); trace(9999, "type") << "type deduced to be " << get(Type, curr->value).name << "$" << end(); return new type_tree(*curr); } @@ -210,27 +243,127 @@ void replace_type_ingredient(type_tree* element_type, string_tree* element_type_ element_type->value = replacement->value; assert(!element_type->left); // since value is set element_type->left = replacement->left ? new type_tree(*replacement->left) : NULL; - assert(!element_type->right); // unsupported + if (element_type->right) delete element_type->right; element_type->right = replacement->right ? new type_tree(*replacement->right) : NULL; const string_tree* replacement_name = nth_type_name(callsite_type_name, type_ingredient_index); element_type_name->value = replacement_name->value; assert(!element_type_name->left); // since value is set element_type_name->left = replacement_name->left ? new string_tree(*replacement_name->left) : NULL; - assert(!element_type_name->right); // unsupported + if (element_type_name->right) delete element_type_name->right; element_type_name->right = replacement_name->right ? new string_tree(*replacement_name->right) : NULL; } replace_type_ingredient(element_type->right, element_type_name->right, callsite_type, callsite_type_name); } +void test_replace_type_ingredient_entire() { + run("container foo:_elem [\n" + " x:_elem\n" + " y:number\n" + "]\n"); + reagent callsite("x:foo:point"); + reagent element = element_type(callsite, 0); + CHECK_EQ(element.name, "x"); + CHECK_EQ(element.properties.at(0).second->value, "point"); + CHECK(!element.properties.at(0).second->right); +} + +void test_replace_type_ingredient_tail() { + run("container foo:_elem [\n" + " x:_elem\n" + "]\n" + "container bar:_elem [\n" + " x:foo:_elem\n" + "]\n"); + reagent callsite("x:bar:point"); + reagent element = element_type(callsite, 0); + CHECK_EQ(element.name, "x"); + CHECK_EQ(element.properties.at(0).second->value, "foo"); + CHECK_EQ(element.properties.at(0).second->right->value, "point"); + CHECK(!element.properties.at(0).second->right->right); +} + +void test_replace_type_ingredient_head_tail_multiple() { + run("container foo:_elem [\n" + " x:_elem\n" + "]\n" + "container bar:_elem [\n" + " x:foo:_elem\n" + "]\n"); + reagent callsite("x:bar:address:shared:array:character"); + reagent element = element_type(callsite, 0); + CHECK_EQ(element.name, "x"); + CHECK_EQ(element.properties.at(0).second->value, "foo"); + CHECK_EQ(element.properties.at(0).second->right->value, "address"); + CHECK_EQ(element.properties.at(0).second->right->right->value, "shared"); + CHECK_EQ(element.properties.at(0).second->right->right->right->value, "array"); + CHECK_EQ(element.properties.at(0).second->right->right->right->right->value, "character"); + CHECK(!element.properties.at(0).second->right->right->right->right->right); +} + +//// generic containers can't yet have type ingredients at non-root position +//// of an element definition +void pending_test_replace_type_ingredient_head_middle() { // not supported yet + run("container foo:_elem [\n" + " x:_elem\n" + "]\n" + "container bar:_elem [\n" + " x:foo:_elem:number\n" + "]\n"); + reagent callsite("x:bar:address"); + reagent element = element_type(callsite, 0); + CHECK_EQ(element.name, "x"); + CHECK_EQ(element.properties.at(0).second->value, "foo"); + CHECK_EQ(element.properties.at(0).second->right->value, "address"); + CHECK_EQ(element.properties.at(0).second->right->right->value, "number"); + CHECK(!element.properties.at(0).second->right->right->right); +} + +void test_replace_last_type_ingredient_with_multiple() { + run("container foo:_a:_b [\n" + " x:_a\n" + " y:_b\n" + "]\n"); + reagent callsite("{f: (foo number (address shared array character))}"); + reagent element = element_type(callsite, 1); + CHECK_EQ(element.name, "y"); + CHECK_EQ(element.properties.at(0).second->value, "address"); + CHECK_EQ(element.properties.at(0).second->right->value, "shared"); + CHECK_EQ(element.properties.at(0).second->right->right->value, "array"); + CHECK_EQ(element.properties.at(0).second->right->right->right->value, "character"); + CHECK(!element.properties.at(0).second->right->right->right->right); +} + +void test_replace_middle_type_ingredient_with_multiple() { + run("container foo:_a:_b:_c [\n" + " x:_a\n" + " y:_b\n" + " z:_c\n" + "]\n"); + reagent callsite("{f: (foo number (address shared array character) boolean)}"); + reagent element = element_type(callsite, 1); + CHECK_EQ(element.name, "y"); + CHECK_EQ(element.properties.at(0).second->value, "address"); + CHECK_EQ(element.properties.at(0).second->right->value, "shared"); + CHECK_EQ(element.properties.at(0).second->right->right->value, "array"); + CHECK_EQ(element.properties.at(0).second->right->right->right->value, "character"); + CHECK(!element.properties.at(0).second->right->right->right->right); +} + const type_tree* nth_type(const type_tree* base, long long int n) { assert(n >= 0); - if (n == 0) return base; + if (n == 0) { + if (base && base->left) return base->left; + return base; + } return nth_type(base->right, n-1); } const string_tree* nth_type_name(const string_tree* base, long long int n) { assert(n >= 0); - if (n == 0) return base; + if (n == 0) { + if (base && base->left) return base->left; + return base; + } return nth_type_name(base->right, n-1); } |