about summary refs log tree commit diff stats
path: root/055shape_shifting_container.cc
diff options
context:
space:
mode:
Diffstat (limited to '055shape_shifting_container.cc')
-rw-r--r--055shape_shifting_container.cc203
1 files changed, 156 insertions, 47 deletions
diff --git a/055shape_shifting_container.cc b/055shape_shifting_container.cc
index a539e34f..131028a5 100644
--- a/055shape_shifting_container.cc
+++ b/055shape_shifting_container.cc
@@ -1,5 +1,14 @@
 //:: Container definitions can contain 'type ingredients'
 
+//: pre-requisite: extend our notion of containers to not necessarily be
+//: atomic types
+:(before "End is_mu_container(type) Special-cases")
+if (!type->atom)
+  return is_mu_container(root_type(type));
+:(before "End is_mu_exclusive_container(type) Special-cases")
+if (!type->atom)
+  return is_mu_exclusive_container(root_type(type));
+
 :(scenario size_of_shape_shifting_container)
 container foo:_t [
   x:_t
@@ -267,10 +276,10 @@ def main [
 
 :(before "End element_type Special-cases")
 replace_type_ingredients(element, type, info);
-:(before "Compute Container Size(element)")
-replace_type_ingredients(element, type, info);
-:(before "Compute Exclusive Container Size(element)")
-replace_type_ingredients(element, type, info);
+:(before "Compute Container Size(element, full_type)")
+replace_type_ingredients(element, full_type, container_info);
+:(before "Compute Exclusive Container Size(element, full_type)")
+replace_type_ingredients(element, full_type, exclusive_container_info);
 :(before "Compute Container Address Offset(element)")
 replace_type_ingredients(element, type, info);
 if (contains_type_ingredient(element)) return;  // error raised elsewhere
@@ -296,63 +305,42 @@ bool contains_type_ingredient(const reagent& x) {
 
 bool contains_type_ingredient(const type_tree* type) {
   if (!type) return false;
-  if (type->value >= START_TYPE_INGREDIENTS) return true;
-  assert(!is_type_ingredient_name(type->name));
+  if (type->atom) return type->value >= START_TYPE_INGREDIENTS;
   return contains_type_ingredient(type->left) || contains_type_ingredient(type->right);
 }
 
 // replace all type_ingredients in element_type with corresponding elements of callsite_type
-// todo: too complicated and likely incomplete; maybe avoid replacing in place?
 void replace_type_ingredients(type_tree* element_type, const type_tree* callsite_type, const type_info& container_info) {
   if (!callsite_type) return;  // error but it's already been raised above
   if (!element_type) return;
-
-  // A. recurse first to avoid nested replaces (which I can't reason about yet)
-  replace_type_ingredients(element_type->left, callsite_type, container_info);
-  replace_type_ingredients(element_type->right, callsite_type, container_info);
+  if (!element_type->atom) {
+    replace_type_ingredients(element_type->left, callsite_type, container_info);
+    replace_type_ingredients(element_type->right, callsite_type, container_info);
+    return;
+  }
   if (element_type->value < START_TYPE_INGREDIENTS) return;
-
   const int type_ingredient_index = element_type->value-START_TYPE_INGREDIENTS;
   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\n" << end();
     return;
   }
+  *element_type = *nth_type_ingredient(callsite_type, type_ingredient_index, container_info);
+}
 
-  // B. replace the current location
-  const type_tree* replacement = NULL;
-  bool zig_left = false;
-  {
-    const type_tree* curr = callsite_type;
-    for (int i = 0; i < type_ingredient_index; ++i)
-      curr = curr->right;
-    if (curr && curr->left) {
-      replacement = curr->left;
-      zig_left = true;
-    }
-    else {
-      // We want foo:_t to be used like foo:number, which expands to {foo: number}
-      // rather than {foo: (number)}
-      // We'd also like to use it with multiple types: foo:address:number.
-      replacement = curr;
-    }
-  }
-  if (element_type->right && replacement->right && zig_left) {  // ZERO confidence that this condition is accurate
-    element_type->name = "";
-    element_type->value = 0;
-    element_type->left = new type_tree(*replacement);
-  }
-  else {
-    string old_name = element_type->name;
-    element_type->name = replacement->name;
-    element_type->value = replacement->value;
-    assert(!element_type->left);  // since value is set
-    element_type->left = replacement->left ? new type_tree(*replacement->left) : NULL;
-    if (zig_left || final_type_ingredient(type_ingredient_index, container_info)) {
-      type_tree* old_right = element_type->right;
-      element_type->right = replacement->right ? new type_tree(*replacement->right) : NULL;
-      append(element_type->right, old_right);
-    }
+const type_tree* nth_type_ingredient(const type_tree* callsite_type, int type_ingredient_index, const type_info& container_info) {
+  bool final = final_type_ingredient(type_ingredient_index, container_info);
+  const type_tree* curr = callsite_type;
+  for (int i = 0; i < type_ingredient_index; ++i) {
+    assert(curr);
+    assert(!curr->atom);
+//?     cerr << "type ingredient " << i << " is " << to_string(curr->left) << '\n';
+    curr = curr->right;
   }
+  assert(curr);
+  if (curr->atom) return curr;
+  if (!final) return curr->left;
+  if (!curr->right) return curr->left;
+  return curr;
 }
 
 bool final_type_ingredient(int type_ingredient_index, const type_info& container_info) {
@@ -482,7 +470,128 @@ def main [
 ]
 +error: illegal type "foo" seems to be missing a type ingredient or three
 
-//: 'merge' on shape-shifting containers
+//:: fix up previous layers
+
+//: We have two transforms in previous layers -- for computing sizes and
+//: offsets containing addresses for containers and exclusive containers --
+//: that we need to teach about type ingredients.
+
+:(before "End compute_container_sizes Non-atom Cases")
+const type_tree* root = root_type(type);
+type_info& info = get(Type, root->value);
+if (info.kind == CONTAINER) {
+  compute_container_sizes(info, type, pending_metadata);
+  return;
+}
+if (info.kind == EXCLUSIVE_CONTAINER) {
+  compute_exclusive_container_sizes(info, type, pending_metadata);
+  return;
+}
+
+:(before "End Unit Tests")
+void test_container_sizes_shape_shifting_container() {
+  run("container foo:_t [\n"
+      "  x:number\n"
+      "  y:_t\n"
+      "]\n");
+  reagent r("x:foo:point");
+  compute_container_sizes(r);
+  CHECK_EQ(r.metadata.size, 3);
+}
+
+void test_container_sizes_shape_shifting_exclusive_container() {
+  run("exclusive-container foo:_t [\n"
+      "  x:number\n"
+      "  y:_t\n"
+      "]\n");
+  reagent r("x:foo:point");
+  compute_container_sizes(r);
+  CHECK_EQ(r.metadata.size, 3);
+  reagent r2("x:foo:number");
+  compute_container_sizes(r2);
+  CHECK_EQ(r2.metadata.size, 2);
+}
+
+void test_container_sizes_compound_type_ingredient() {
+  run("container foo:_t [\n"
+      "  x:number\n"
+      "  y:_t\n"
+      "]\n");
+  reagent r("x:foo:address:point");
+  compute_container_sizes(r);
+  CHECK_EQ(r.metadata.size, 2);
+  // scan also pre-computes metadata for type ingredient
+  reagent point("x:point");
+  CHECK(contains_key(Container_metadata, point.type));
+  CHECK_EQ(get(Container_metadata, point.type).size, 2);
+}
+
+void test_container_sizes_recursive_shape_shifting_container() {
+  run("container foo:_t [\n"
+      "  x:number\n"
+      "  y:address:foo:_t\n"
+      "]\n");
+  reagent r2("x:foo:number");
+  compute_container_sizes(r2);
+  CHECK_EQ(r2.metadata.size, 2);
+}
+
+:(before "End compute_container_address_offsets Non-atom Cases")
+const type_tree* root = root_type(type);
+type_info& info = get(Type, root->value);
+if (info.kind == CONTAINER) {
+  compute_container_address_offsets(info, type);
+  return;
+}
+if (info.kind == EXCLUSIVE_CONTAINER) {
+  compute_exclusive_container_address_offsets(info, type);
+  return;
+}
+
+:(before "End Unit Tests")
+void test_container_address_offsets_in_shape_shifting_container() {
+  run("container foo:_t [\n"
+      "  x:number\n"
+      "  y:_t\n"
+      "]\n");
+  reagent r("x:foo:address:number");
+  compute_container_sizes(r);
+  compute_container_address_offsets(r);
+  CHECK_EQ(SIZE(r.metadata.address), 1);
+  CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
+  set<address_element_info>& offset_info = get(r.metadata.address, set<tag_condition_info>());
+  CHECK_EQ(SIZE(offset_info), 1);
+  CHECK_EQ(offset_info.begin()->offset, 1);  //
+  CHECK(offset_info.begin()->payload_type->atom);
+  CHECK_EQ(offset_info.begin()->payload_type->name, "number");
+}
+
+void test_container_address_offsets_in_nested_shape_shifting_container() {
+  run("container foo:_t [\n"
+      "  x:number\n"
+      "  y:_t\n"
+      "]\n"
+      "container bar:_t [\n"
+      "  x:_t\n"
+      "  y:foo:_t\n"
+      "]\n");
+  reagent r("x:bar:address:number");
+  CLEAR_TRACE;
+  compute_container_sizes(r);
+  compute_container_address_offsets(r);
+  CHECK_EQ(SIZE(r.metadata.address), 1);
+  CHECK(contains_key(r.metadata.address, set<tag_condition_info>()));
+  set<address_element_info>& offset_info = get(r.metadata.address, set<tag_condition_info>());
+  CHECK_EQ(SIZE(offset_info), 2);
+  CHECK_EQ(offset_info.begin()->offset, 0);  //
+  CHECK(offset_info.begin()->payload_type->atom);
+  CHECK_EQ(offset_info.begin()->payload_type->name, "number");
+  CHECK_EQ((++offset_info.begin())->offset, 2);  //
+  CHECK((++offset_info.begin())->payload_type->atom);
+  CHECK_EQ((++offset_info.begin())->payload_type->name, "number");
+}
+
+//:: 'merge' on shape-shifting containers
 
 :(scenario merge_check_shape_shifting_container_containing_exclusive_container)
 container foo:_elem [