about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--030container.cc26
-rw-r--r--058generic_container.cc46
2 files changed, 61 insertions, 11 deletions
diff --git a/030container.cc b/030container.cc
index 1bece91d..9618dd2a 100644
--- a/030container.cc
+++ b/030container.cc
@@ -152,10 +152,9 @@ case GET: {
     raise_error << maybe(Recipe[r].name) << "invalid offset " << offset_value << " for " << Type[base_type].name << '\n' << end();
     break;
   }
-  reagent product = inst.products.at(0);
+  reagent& product = inst.products.at(0);
   // Update GET product in Check
-  reagent element;
-  element.type = new type_tree(*Type[base_type].elements.at(offset_value));
+  const reagent element = element_type(base, offset_value);
   if (!types_match(product, element)) {
     raise_error << maybe(Recipe[r].name) << "'get' " << offset.original_string << " (" << offset_value << ") on " << Type[base_type].name << " can't be saved in " << product.original_string << "; type should be " << dump_types(element) << '\n' << end();
     break;
@@ -180,15 +179,25 @@ case GET: {
     src += size_of(Type[base_type].elements.at(i));
   }
   trace(9998, "run") << "address to copy is " << src << end();
-  type_ordinal src_type = Type[base_type].elements.at(offset)->value;
-  trace(9998, "run") << "its type is " << Type[src_type].name << end();
-  reagent tmp;
+  reagent tmp = element_type(base, offset);
   tmp.set_value(src);
-  tmp.type = new type_tree(src_type);
+  trace(9998, "run") << "its type is " << dump_types(tmp) << end();
   products.push_back(read_memory(tmp));
   break;
 }
 
+:(code)
+const reagent element_type(const reagent& canonized_base, long long int offset_value) {
+  assert(offset_value >= 0);
+  assert(Type.find(canonized_base.type->value) != Type.end());
+  const type_info& info = Type[canonized_base.type->value];
+  assert(info.kind == CONTAINER);
+  reagent element;
+  element.type = new type_tree(*info.elements.at(offset_value));
+  // End element_type Special-cases
+  return element;
+}
+
 :(scenario get_handles_nested_container_elements)
 recipe main [
   12:number <- copy 34
@@ -273,9 +282,8 @@ case GET_ADDRESS: {
   }
   reagent product = inst.products.at(0);
   // Update GET_ADDRESS product in Check
-  reagent element;
   // same type as for GET..
-  element.type = new type_tree(*Type[base_type].elements.at(offset_value));
+  reagent element = element_type(base, offset_value);
   // ..except for an address at the start
   element.type = new type_tree(Type_ordinal["address"], element.type);
   if (!types_match(product, element)) {
diff --git a/058generic_container.cc b/058generic_container.cc
index b192dbc3..d5368765 100644
--- a/058generic_container.cc
+++ b/058generic_container.cc
@@ -91,7 +91,7 @@ long long int size_of_type_ingredient(const type_tree* element_template, const t
   }
   assert(curr);
   assert(!curr->left);  // unimplemented
-  trace(9999, "type") << "type deduced to be " << Type[curr->value].name << "$\n";
+  trace(9999, "type") << "type deduced to be " << Type[curr->value].name << "$";
   type_tree tmp(curr->value);
   if (curr->right)
     tmp.right = new type_tree(*curr->right);
@@ -105,7 +105,7 @@ container foo:_t [
 ]
 recipe main [
   1:foo:point <- merge 14, 15, 16
-  2:number <- get 1:foo:point, 1:offset
+  2:number <- get 1:foo:point, y:offset
 ]
 +mem: storing 16 in location 2
 
@@ -115,6 +115,48 @@ if (Type[base_type].elements.at(i)->value >= START_TYPE_INGREDIENTS) {
   continue;
 }
 
+:(scenario get_on_generic_container_2)
+container foo:_t [
+  x:_t
+  y:number
+]
+recipe main [
+  1:foo:point <- merge 14, 15, 16
+  2:point <- get 1:foo:point, x:offset
+]
++mem: storing 14 in location 2
++mem: storing 15 in location 3
+
+:(before "End element_type Special-cases")
+if (contains_type_ingredient(element)) {
+  replace_type_ingredients(element.type, canonized_base.type->right);
+}
+
+:(code)
+bool contains_type_ingredient(const reagent& x) {
+  return contains_type_ingredient(x.type);
+}
+
+bool contains_type_ingredient(const type_tree* type) {
+  if (!type) return false;
+  if (type->value >= START_TYPE_INGREDIENTS) return true;
+  return contains_type_ingredient(type->left) || contains_type_ingredient(type->right);
+}
+
+void replace_type_ingredients(type_tree* element_type, type_tree* callsite_type) {
+  if (!element_type) return;
+  if (element_type->value >= START_TYPE_INGREDIENTS) {
+    element_type->value = nth_type(callsite_type, element_type->value-START_TYPE_INGREDIENTS);
+  }
+  replace_type_ingredients(element_type->right, callsite_type->right);
+}
+
+type_ordinal nth_type(type_tree* base, long long int n) {
+  assert(n >= 0);
+  if (n == 0) return base->value;  // todo: base->left
+  return nth_type(base->right, n-1);
+}
+
 :(scenario get_address_on_generic_container)
 container foo:_t [
   x:_t