about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--030container.cc2
-rw-r--r--058shape_shifting_container.cc155
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);
 }
 
span class="ni">&nbsp;used<br> instead&nbsp;of&nbsp;this&nbsp;one.&nbsp;&nbsp;Though,&nbsp;to&nbsp;minimize&nbsp;your&nbsp;effort&nbsp;when&nbsp;upgrading&nbsp;ranger,<br> you&nbsp;may&nbsp;want&nbsp;to&nbsp;subclass&nbsp;<a href="#CustomApplications">CustomApplications</a>&nbsp;rather&nbsp;than&nbsp;making&nbsp;a&nbsp;full&nbsp;copy.<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br> This&nbsp;example&nbsp;modifies&nbsp;the&nbsp;behaviour&nbsp;of&nbsp;"feh"&nbsp;and&nbsp;adds&nbsp;a&nbsp;custom&nbsp;media&nbsp;player:<br> &nbsp;<br> ####&nbsp;start&nbsp;of&nbsp;the&nbsp;~/.ranger/apps.py&nbsp;example<br> from&nbsp;ranger.defaults.apps&nbsp;import&nbsp;<a href="#CustomApplications">CustomApplications</a>&nbsp;as&nbsp;DefaultApps<br> from&nbsp;ranger.api.apps&nbsp;import&nbsp;*<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br> class&nbsp;<a href="#CustomApplications">CustomApplications</a>(DefaultApps):<br> &nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;app_kaffeine(self,&nbsp;c):<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;tup('kaffeine',&nbsp;*c)<br> &nbsp;<br> &nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;app_feh_fullscreen_by_default(self,&nbsp;c):<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;tup('feh',&nbsp;'-F',&nbsp;*c)<br> &nbsp;<br> &nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;app_default(self,&nbsp;c):<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;c.file.video&nbsp;or&nbsp;c.file.audio:<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;app_kaffeine(c)<br> &nbsp;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;c.file.image&nbsp;and&nbsp;c.mode&nbsp;==&nbsp;0:<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;app_feh_fullscreen_by_default(c)<br> &nbsp;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;DefaultApps.app_default(self,&nbsp;c)<br> ####&nbsp;end&nbsp;of&nbsp;the&nbsp;example</tt></p> <p> <table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section"> <tr bgcolor="#aa55cc"> <td colspan=3 valign=bottom>&nbsp;<br> <font color="#ffffff" face="helvetica, arial"><big><strong>Modules</strong></big></font></td></tr> <tr><td bgcolor="#aa55cc"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td> <td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="os.html">os</a><br> </td><td width="25%" valign=top><a href="re.html">re</a><br> </td><td width="25%" valign=top><a href="sys.html">sys</a><br> </td><td width="25%" valign=top></td></tr></table></td></tr></table><p> <table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section"> <tr bgcolor="#ee77aa"> <td colspan=3 valign=bottom>&nbsp;<br> <font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr> <tr><td bgcolor="#ee77aa"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td> <td width="100%"><dl> <dt><font face="helvetica, arial"><a href="ranger.api.apps.html#Applications">ranger.api.apps.Applications</a>(<a href="ranger.shared.html#FileManagerAware">ranger.shared.FileManagerAware</a>) </font></dt><dd> <dl> <dt><font face="helvetica, arial"><a href="ranger.defaults.apps.html#CustomApplications">CustomApplications</a> </font></dt></dl> </dd> </dl> <p> <table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section"> <tr bgcolor="#ffc8d8"> <td colspan=3 valign=bottom>&nbsp;<br> <font color="#000000" face="helvetica, arial"><a name="CustomApplications">class <strong>CustomApplications</strong></a>(<a href="ranger.api.apps.html#Applications">ranger.api.apps.Applications</a>)</font></td></tr> <tr><td bgcolor="#ffc8d8"><tt>&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td> <td width="100%"><dl><dt>Method resolution order:</dt> <dd><a href="ranger.defaults.apps.html#CustomApplications">CustomApplications</a></dd> <dd><a href="ranger.api.apps.html#Applications">ranger.api.apps.Applications</a></dd> <dd><a href="ranger.shared.html#FileManagerAware">ranger.shared.FileManagerAware</a></dd> <dd><a href="ranger.shared.html#Awareness">ranger.shared.Awareness</a></dd> <dd><a href="__builtin__.html#object">__builtin__.object</a></dd> </dl> <hr> Methods defined here:<br> <dl><dt><a name="CustomApplications-app_apvlv"><strong>app_apvlv</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_aunpack"><strong>app_aunpack</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_default"><strong>app_default</strong></a>(self, c)</dt><dd><tt>How&nbsp;to&nbsp;determine&nbsp;the&nbsp;default&nbsp;application?</tt></dd></dl> <dl><dt><a name="CustomApplications-app_edit_or_run"><strong>app_edit_or_run</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_editor"><strong>app_editor</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_elinks"><strong>app_elinks</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_evince"><strong>app_evince</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_feh"><strong>app_feh</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_firefox"><strong>app_firefox</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_java"><strong>app_java</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_javac"><strong>app_javac</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_make"><strong>app_make</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_mplayer"><strong>app_mplayer</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_opera"><strong>app_opera</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_pager"><strong>app_pager</strong></a>(self, c)</dt><dd><tt>#&nbsp;-----------------------------------------&nbsp;application&nbsp;definitions</tt></dd></dl> <dl><dt><a name="CustomApplications-app_totem"><strong>app_totem</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_vim"><strong>app_vim</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_wine"><strong>app_wine</strong></a>(self, c)</dt></dl> <dl><dt><a name="CustomApplications-app_zsnes"><strong>app_zsnes</strong></a>(self, c)</dt></dl> <hr> Methods inherited from <a href="ranger.api.apps.html#Applications">ranger.api.apps.Applications</a>:<br> <dl><dt><a name="CustomApplications-all"><strong>all</strong></a>(self)</dt><dd><tt>Returns&nbsp;a&nbsp;list&nbsp;with&nbsp;all&nbsp;application&nbsp;functions</tt></dd></dl> <dl><dt><a name="CustomApplications-app_self"><strong>app_self</strong></a>(self, context)</dt><dd><tt>Run&nbsp;the&nbsp;file&nbsp;itself</tt></dd></dl> <dl><dt><a name="CustomApplications-apply"><strong>apply</strong></a>(self, app, context)</dt></dl> <dl><dt><a name="CustomApplications-either"><strong>either</strong></a>(self, context, *args)</dt></dl> <dl><dt><a name="CustomApplications-get"><strong>get</strong></a>(self, app)</dt><dd><tt>Looks&nbsp;for&nbsp;an&nbsp;application,&nbsp;returns&nbsp;app_default&nbsp;if&nbsp;it&nbsp;doesn't&nbsp;exist</tt></dd></dl> <dl><dt><a name="CustomApplications-has"><strong>has</strong></a>(self, app)</dt><dd><tt>Returns&nbsp;whether&nbsp;an&nbsp;application&nbsp;is&nbsp;defined</tt></dd></dl> <hr> Data and other attributes inherited from <a href="ranger.shared.html#FileManagerAware">ranger.shared.FileManagerAware</a>:<br> <dl><dt><strong>fm</strong> = None</dl> <hr> Data descriptors inherited from <a href="ranger.shared.html#Awareness">ranger.shared.Awareness</a>:<br> <dl><dt><strong>__dict__</strong></dt> <dd><tt>dictionary&nbsp;for&nbsp;instance&nbsp;variables&nbsp;(if&nbsp;defined)</tt></dd> </dl> <dl><dt><strong>__weakref__</strong></dt> <dd><tt>list&nbsp;of&nbsp;weak&nbsp;references&nbsp;to&nbsp;the&nbsp;object&nbsp;(if&nbsp;defined)</tt></dd> </dl> </td></tr></table></td></tr></table><p> <table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section"> <tr bgcolor="#55aa55"> <td colspan=3 valign=bottom>&nbsp;<br> <font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr> <tr><td bgcolor="#55aa55"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td> <td width="100%"><strong>INTERPRETED_LANGUAGES</strong> = &lt;_sre.SRE_Pattern object at 0xf6f2d0&gt;<br> <strong>PIPE</strong> = -1</td></tr></table> </body></html>