about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-09-23 23:07:58 -0700
committerKartik K. Agaram <vc@akkartik.com>2016-09-23 23:07:58 -0700
commit203563b3465fe5f25f97e475b1a4dbe957845030 (patch)
treef6112083d29a9639109e2cde7e3075a36e3cb1b5
parentd587411f9da46f72cd99c966cfe3150b5e72baab (diff)
downloadmu-203563b3465fe5f25f97e475b1a4dbe957845030.tar.gz
3412
-rw-r--r--html/010vm.cc.html4
-rw-r--r--html/057immutable.cc.html19
-rw-r--r--html/091socket.cc.html50
-rw-r--r--html/101run_sandboxed.cc.html16
-rw-r--r--html/server-socket.mu.html53
5 files changed, 88 insertions, 54 deletions
diff --git a/html/010vm.cc.html b/html/010vm.cc.html
index e539a833..3955c7cd 100644
--- a/html/010vm.cc.html
+++ b/html/010vm.cc.html
@@ -278,6 +278,10 @@ restore_snapshots<span class="Delimiter">();</span>
 <span class="Normal">void</span> restore_snapshots<span class="Delimiter">()</span> <span class="Delimiter">{</span>
   Recipe = Recipe_snapshot<span class="Delimiter">;</span>
   Recipe_ordinal = Recipe_ordinal_snapshot<span class="Delimiter">;</span>
+  restore_non_recipe_snapshots<span class="Delimiter">();</span>
+<span class="Delimiter">}</span>
+<span class="Comment">// when running sandboxes in the edit/ app we'll want to restore everything except recipes defined in the app</span>
+<span class="Normal">void</span> restore_non_recipe_snapshots<span class="Delimiter">()</span> <span class="Delimiter">{</span>
   Type_ordinal = Type_ordinal_snapshot<span class="Delimiter">;</span>
   Type = Type_snapshot<span class="Delimiter">;</span>
   <span class="Comment">// End restore_snapshots</span>
diff --git a/html/057immutable.cc.html b/html/057immutable.cc.html
index b74dbcb5..94d6d42f 100644
--- a/html/057immutable.cc.html
+++ b/html/057immutable.cc.html
@@ -250,9 +250,6 @@ $error: <span class="Constant">0</span>
 
 <span class="Delimiter">:(scenario cannot_modify_address_inside_immutable_ingredients_3)</span>
 <span class="Special">% Hide_errors = true;</span>
-container foo [
-  <span class="Normal">x</span>:num
-]
 def main [
   <span class="Comment"># don't run anything</span>
 ]
@@ -265,9 +262,6 @@ def foo a:&amp;:@:&amp;:num [
 <span class="traceContains">+error: foo: cannot modify 'x' in instruction '*x &lt;- copy 34' because that would modify a which is an ingredient of recipe foo but not also a product</span>
 
 <span class="Delimiter">:(scenario cannot_modify_address_inside_immutable_ingredients_4)</span>
-container foo [
-  <span class="Normal">x</span>:&amp;:@:num  <span class="Comment"># contains an address</span>
-]
 def main [
   <span class="Comment"># don't run anything</span>
 ]
@@ -281,6 +275,18 @@ def foo a:&amp;:@:&amp;:num [
 ]
 $error: <span class="Constant">0</span>
 
+<span class="Delimiter">:(scenario latter_ingredient_of_index_is_immutable)</span>
+def main [
+  <span class="Comment"># don't run anything</span>
+]
+def foo a:&amp;:@:&amp;:@:num<span class="Delimiter">,</span> b:num <span class="Delimiter">-&gt;</span> a:&amp;:@:&amp;:@:num [
+  local-scope
+  load-ingredients
+  <span class="Normal">x</span>:&amp;:@:num<span class="Special"> &lt;- </span>index *a<span class="Delimiter">,</span> b
+  *x<span class="Special"> &lt;- </span>put-index *x<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">,</span> <span class="Constant">34</span>
+]
+$error: <span class="Constant">0</span>
+
 <span class="Delimiter">:(scenario can_traverse_immutable_ingredients)</span>
 container test-list [
   <span class="Normal">next</span>:&amp;:test-list
@@ -383,6 +389,7 @@ Transform<span class="Delimiter">.</span>push_back<span class="Delimiter">(</spa
     <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>caller<span class="Delimiter">.</span>steps<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
       <span class="Normal">const</span> instruction&amp; inst = caller<span class="Delimiter">.</span>steps<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span>
       check_immutable_ingredient_in_instruction<span class="Delimiter">(</span>inst<span class="Delimiter">,</span> immutable_vars<span class="Delimiter">,</span> current_ingredient<span class="Delimiter">.</span>name<span class="Delimiter">,</span> caller<span class="Delimiter">);</span>
+      <span class="Normal">if</span> <span class="Delimiter">(</span>inst<span class="Delimiter">.</span>operation == INDEX &amp;&amp; inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>name == current_ingredient<span class="Delimiter">.</span>name<span class="Delimiter">)</span> <span class="Identifier">continue</span><span class="Delimiter">;</span>
       update_aliases<span class="Delimiter">(</span>inst<span class="Delimiter">,</span> immutable_vars<span class="Delimiter">);</span>
     <span class="Delimiter">}</span>
   <span class="Delimiter">}</span>
diff --git a/html/091socket.cc.html b/html/091socket.cc.html
index a33755ef..d5f01e41 100644
--- a/html/091socket.cc.html
+++ b/html/091socket.cc.html
@@ -14,12 +14,13 @@ pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-
 body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color: #080808; }
 * { font-size: 12pt; font-size: 1em; }
 .Constant { color: #00a0a0; }
+.Comment { color: #9090ff; }
 .cSpecial { color: #008000; }
 .Delimiter { color: #800080; }
 .Identifier { color: #fcb165; }
 .Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; }
 .PreProc { color: #800080; }
-.Comment { color: #9090ff; }
+.CommentedCode { color: #6c6c6c; }
 -->
 </style>
 
@@ -49,7 +50,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 <span class="Delimiter">:(code)</span>
 <span class="Normal">void</span> server_socket<span class="Delimiter">(</span><span class="Normal">int</span> portno<span class="Delimiter">,</span> socket_t* server<span class="Delimiter">)</span> <span class="Delimiter">{</span>
   server<span class="Delimiter">-&gt;</span>fd = socket<span class="Delimiter">(</span>AF_INET<span class="Delimiter">,</span> SOCK_STREAM<span class="Delimiter">,</span> <span class="Constant">0</span><span class="Delimiter">);</span>
-  <span class="Normal">int</span> dummy<span class="Delimiter">;</span>
+  <span class="Normal">int</span> dummy = <span class="Constant">0</span><span class="Delimiter">;</span>
   setsockopt<span class="Delimiter">(</span>server<span class="Delimiter">-&gt;</span>fd<span class="Delimiter">,</span> SOL_SOCKET<span class="Delimiter">,</span> SO_REUSEADDR<span class="Delimiter">,</span> &amp;dummy<span class="Delimiter">,</span> <span class="Normal">sizeof</span><span class="Delimiter">(</span>dummy<span class="Delimiter">));</span>
   server<span class="Delimiter">-&gt;</span>addr<span class="Delimiter">.</span>sin_family = AF_INET<span class="Delimiter">;</span>
   server<span class="Delimiter">-&gt;</span>addr<span class="Delimiter">.</span>sin_addr<span class="Delimiter">.</span>s_addr = INADDR_ANY<span class="Delimiter">;</span>
@@ -148,24 +149,20 @@ _READ_FROM_SOCKET<span class="Delimiter">,</span>
 put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;$read-from-socket&quot;</span><span class="Delimiter">,</span> _READ_FROM_SOCKET<span class="Delimiter">);</span>
 <span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span>
 <span class="Normal">case</span> _READ_FROM_SOCKET: <span class="Delimiter">{</span>
-  <span class="Normal">if</span> <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">)</span> != <span class="Constant">1</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
-    raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;'$read-from-socket' requires exactly one ingredient, but got '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
+  <span class="Normal">if</span> <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">)</span> != <span class="Constant">2</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
+    raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;'$read-from-socket' requires exactly two ingredients, but got '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
     <span class="Identifier">break</span><span class="Delimiter">;</span>
   <span class="Delimiter">}</span>
   <span class="Normal">if</span> <span class="Delimiter">(</span>!is_mu_number<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span>
     raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;first ingredient of '$read-from-socket' should be a number, but got '&quot;</span> &lt;&lt; to_string<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">))</span> &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
     <span class="Identifier">break</span><span class="Delimiter">;</span>
   <span class="Delimiter">}</span>
-  <span class="Normal">if</span> <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">)</span> != <span class="Constant">2</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
-    raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;'$read-from-socket' requires exactly one product, but got '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
-    <span class="Identifier">break</span><span class="Delimiter">;</span>
-  <span class="Delimiter">}</span>
-  <span class="Normal">if</span> <span class="Delimiter">(</span>!is_mu_character<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span>
-    raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;first product of '$read-from-socket' should be a character, but got '&quot;</span> &lt;&lt; to_string<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">))</span> &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
+  <span class="Normal">if</span> <span class="Delimiter">(</span>!is_mu_number<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span>
+    raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;second ingredient of '$read-from-socket' should be a number, but got '&quot;</span> &lt;&lt; to_string<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">))</span> &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
     <span class="Identifier">break</span><span class="Delimiter">;</span>
   <span class="Delimiter">}</span>
-  <span class="Normal">if</span> <span class="Delimiter">(</span>!is_mu_boolean<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span>
-    raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;second product of '$read-from-socket' should be a boolean but got '&quot;</span> &lt;&lt; to_string<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">))</span> &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
+  <span class="Normal">if</span> <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">)</span> != <span class="Constant">2</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
+    raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;'$read-from-socket' requires exactly two product, but got '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
     <span class="Identifier">break</span><span class="Delimiter">;</span>
   <span class="Delimiter">}</span>
   <span class="Identifier">break</span><span class="Delimiter">;</span>
@@ -173,20 +170,16 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span
 <span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span>
 <span class="Normal">case</span> _READ_FROM_SOCKET: <span class="Delimiter">{</span>
   <span class="Normal">long</span> <span class="Normal">long</span> <span class="Normal">int</span> x = <span class="Normal">static_cast</span>&lt;<span class="Normal">long</span> <span class="Normal">long</span> <span class="Normal">int</span>&gt;<span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span>
+  <span class="Normal">int</span> bytes = <span class="Normal">static_cast</span>&lt;<span class="Normal">int</span>&gt;<span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span> <span class="CommentedCode">//? Should this be something with more bytes?</span>
   socket_t* socket = <span class="Normal">reinterpret_cast</span>&lt;socket_t*&gt;<span class="Delimiter">(</span>x<span class="Delimiter">);</span>
   <span class="Normal">int</span> socket_fd = socket<span class="Delimiter">-&gt;</span>fd<span class="Delimiter">;</span>
-  <span class="Normal">char</span> single_char[<span class="Constant">2</span>]<span class="Delimiter">;</span>
-  bzero<span class="Delimiter">(</span>single_char<span class="Delimiter">,</span> <span class="Constant">2</span><span class="Delimiter">);</span>
-  <span class="Normal">int</span> bytes_read = read<span class="Delimiter">(</span>socket_fd<span class="Delimiter">,</span> single_char<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
+  <span class="Normal">char</span> contents[bytes]<span class="Delimiter">;</span>
+  bzero<span class="Delimiter">(</span>contents<span class="Delimiter">,</span> bytes<span class="Delimiter">);</span>
+  <span class="Normal">int</span> bytes_read = read<span class="Delimiter">(</span>socket_fd<span class="Delimiter">,</span> contents<span class="Delimiter">,</span> bytes - <span class="Constant">1</span> <span class="Comment">/*</span><span class="Comment"> null-terminated </span><span class="Comment">*/</span><span class="Delimiter">);</span>
+  <span class="Comment">//?: cerr &lt;&lt; &quot;Read:\n&quot; &lt;&lt; string(contents) &lt;&lt; &quot;\n&quot;;</span>
   products<span class="Delimiter">.</span>resize<span class="Delimiter">(</span><span class="Constant">2</span><span class="Delimiter">);</span>
-  <span class="Normal">if</span> <span class="Delimiter">(</span>single_char[<span class="Constant">0</span>]== <span class="Constant">EOF</span> || bytes_read == <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
-    products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>push_back<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">);</span>  <span class="Comment">// eof</span>
-  <span class="Delimiter">}</span>
-  <span class="Normal">else</span> <span class="Delimiter">{</span>
-    products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>push_back<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span>
-  <span class="Delimiter">}</span>
-  products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>push_back<span class="Delimiter">(</span>single_char[<span class="Constant">0</span>]<span class="Delimiter">);</span>
-  <span class="Identifier">break</span><span class="Delimiter">;</span>
+  products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>push_back<span class="Delimiter">(</span>new_mu_text<span class="Delimiter">(</span>string<span class="Delimiter">(</span>contents<span class="Delimiter">)));</span>
+  products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>push_back<span class="Delimiter">(</span>bytes_read<span class="Delimiter">);</span>
   <span class="Identifier">break</span><span class="Delimiter">;</span>
 <span class="Delimiter">}</span>
 
@@ -223,11 +216,11 @@ _CLOSE_SOCKET<span class="Delimiter">,</span>
 put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;$close-socket&quot;</span><span class="Delimiter">,</span> _CLOSE_SOCKET<span class="Delimiter">);</span>
 <span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span>
 <span class="Normal">case</span> _CLOSE_SOCKET: <span class="Delimiter">{</span>
-  <span class="Normal">if</span> <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">)</span> != <span class="Constant">2</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
+  <span class="Normal">if</span> <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">)</span> != <span class="Constant">1</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
     raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;'$close-socket' requires exactly two ingredient, but got '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
     <span class="Identifier">break</span><span class="Delimiter">;</span>
   <span class="Delimiter">}</span>
-  <span class="Normal">if</span> <span class="Delimiter">(</span>!is_mu_number<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">))</span> || !is_mu_number<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span>
+  <span class="Normal">if</span> <span class="Delimiter">(</span>!is_mu_number<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span>
     raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;first ingredient of '$close-socket' should be a character, but got '&quot;</span> &lt;&lt; to_string<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">))</span> &lt;&lt; <span class="Constant">&quot;t</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
     <span class="Identifier">break</span><span class="Delimiter">;</span>
   <span class="Delimiter">}</span>
@@ -235,10 +228,9 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span
 <span class="Delimiter">}</span>
 <span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span>
 <span class="Normal">case</span> _CLOSE_SOCKET: <span class="Delimiter">{</span>
-  <span class="Normal">double</span> socket_fd = ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span>
-  <span class="Normal">double</span> session_fd = ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span>
-  close<span class="Delimiter">(</span>socket_fd<span class="Delimiter">);</span>
-  close<span class="Delimiter">(</span>session_fd<span class="Delimiter">);</span>
+  <span class="Normal">long</span> <span class="Normal">long</span> <span class="Normal">int</span> x = <span class="Normal">static_cast</span>&lt;<span class="Normal">long</span> <span class="Normal">long</span> <span class="Normal">int</span>&gt;<span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span>
+  socket_t* socket = <span class="Normal">reinterpret_cast</span>&lt;socket_t*&gt;<span class="Delimiter">(</span>x<span class="Delimiter">);</span>
+  close<span class="Delimiter">(</span>socket<span class="Delimiter">-&gt;</span>fd<span class="Delimiter">);</span>
   <span class="Identifier">break</span><span class="Delimiter">;</span>
 <span class="Delimiter">}</span>
 </pre>
diff --git a/html/101run_sandboxed.cc.html b/html/101run_sandboxed.cc.html
index e12ec509..563c6d3a 100644
--- a/html/101run_sandboxed.cc.html
+++ b/html/101run_sandboxed.cc.html
@@ -169,6 +169,7 @@ map&lt;string<span class="Delimiter">,</span> type_ordinal&gt; Type_ordinal_snap
 map&lt;type_ordinal<span class="Delimiter">,</span> type_info&gt; Type_snapshot_stash<span class="Delimiter">;</span>
 map&lt;recipe_ordinal<span class="Delimiter">,</span> map&lt;string<span class="Delimiter">,</span> <span class="Normal">int</span>&gt; &gt; Name_snapshot_stash<span class="Delimiter">;</span>
 map&lt;string<span class="Delimiter">,</span> vector&lt;recipe_ordinal&gt; &gt; Recipe_variants_snapshot_stash<span class="Delimiter">;</span>
+map&lt;string<span class="Delimiter">,</span> type_tree*&gt; Type_abbreviations_snapshot_stash<span class="Delimiter">;</span>
 
 <span class="Delimiter">:(code)</span>
 <span class="Normal">void</span> run_code_begin<span class="Delimiter">(</span><span class="Normal">bool</span> should_stash_snapshots<span class="Delimiter">)</span> <span class="Delimiter">{</span>
@@ -211,6 +212,8 @@ map&lt;string<span class="Delimiter">,</span> vector&lt;recipe_ordinal&gt; &gt;
   Name_snapshot_stash = Name_snapshot<span class="Delimiter">;</span>
   assert<span class="Delimiter">(</span>Recipe_variants_snapshot_stash<span class="Delimiter">.</span>empty<span class="Delimiter">());</span>
   Recipe_variants_snapshot_stash = Recipe_variants_snapshot<span class="Delimiter">;</span>
+  assert<span class="Delimiter">(</span>Type_abbreviations_snapshot_stash<span class="Delimiter">.</span>empty<span class="Delimiter">());</span>
+  Type_abbreviations_snapshot_stash = Type_abbreviations_snapshot<span class="Delimiter">;</span>
   save_snapshots<span class="Delimiter">();</span>
 <span class="Delimiter">}</span>
 <span class="Normal">void</span> unstash_snapshots<span class="Delimiter">()</span> <span class="Delimiter">{</span>
@@ -221,6 +224,7 @@ map&lt;string<span class="Delimiter">,</span> vector&lt;recipe_ordinal&gt; &gt;
   Type_snapshot = Type_snapshot_stash<span class="Delimiter">;</span>  Type_snapshot_stash<span class="Delimiter">.</span>clear<span class="Delimiter">();</span>
   Name_snapshot = Name_snapshot_stash<span class="Delimiter">;</span>  Name_snapshot_stash<span class="Delimiter">.</span>clear<span class="Delimiter">();</span>
   Recipe_variants_snapshot = Recipe_variants_snapshot_stash<span class="Delimiter">;</span>  Recipe_variants_snapshot_stash<span class="Delimiter">.</span>clear<span class="Delimiter">();</span>
+  Type_abbreviations_snapshot = Type_abbreviations_snapshot_stash<span class="Delimiter">;</span>  Type_abbreviations_snapshot_stash<span class="Delimiter">.</span>clear<span class="Delimiter">();</span>
 <span class="Delimiter">}</span>
 
 <span class="Delimiter">:(before &quot;End Load Recipes&quot;)</span>
@@ -507,17 +511,7 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span
 <span class="Delimiter">}</span>
 <span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span>
 <span class="Normal">case</span> RELOAD: <span class="Delimiter">{</span>
-  <span class="Comment">// conundrum: need to support repeated reloads of the same code, but not</span>
-  <span class="Comment">// wipe out state for the current test</span>
-  <span class="Comment">// hacky solution: subset of restore_snapshots() without restoring recipes {</span>
-  <span class="Comment">// can't yet define containers in a test that runs 'reload'</span>
-  Type_ordinal = Type_ordinal_snapshot<span class="Delimiter">;</span>
-  Type = Type_snapshot<span class="Delimiter">;</span>
-  <span class="Comment">// can't yet create new specializations of shape-shifting recipes in a test</span>
-  <span class="Comment">// that runs 'reload'</span>
-  Recipe_variants = Recipe_variants_snapshot<span class="Delimiter">;</span>
-  Name = Name_snapshot<span class="Delimiter">;</span>
-  <span class="Comment">// }</span>
+  restore_non_recipe_snapshots<span class="Delimiter">();</span>
   string code = read_mu_text<span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span>
   run_code_begin<span class="Delimiter">(</span><span class="Comment">/*</span><span class="Comment">should_stash_snapshots</span><span class="Comment">*/</span><span class="Constant">false</span><span class="Delimiter">);</span>
   routine* save_current_routine = Current_routine<span class="Delimiter">;</span>
diff --git a/html/server-socket.mu.html b/html/server-socket.mu.html
index 0095f59a..5bb09e1f 100644
--- a/html/server-socket.mu.html
+++ b/html/server-socket.mu.html
@@ -15,6 +15,7 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 * { font-size: 12pt; font-size: 1em; }
 .muRecipe { color: #ff8700; }
 .Delimiter { color: #800080; }
+.Comment { color: #9090ff; }
 .Constant { color: #00a0a0; }
 .Special { color: #c00000; }
 .muControl { color: #c0a020; }
@@ -29,22 +30,36 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
 </head>
 <body>
 <pre id='vimCodeElement'>
+<span class="Comment"># Example of reading from a socket using channels and writing back to it</span>
+<span class="Comment"># directly. Running this file and navigating to &lt;address of server&gt;:8080</span>
+<span class="Comment"># should result in your browser displaying &quot;SUCCESS!&quot;.</span>
+<span class="Comment">#</span>
+<span class="Comment"># Unfortunately, the reading implementation has some redundant, inelegant</span>
+<span class="Comment"># code to make up for my lack of insight into Linux's socket internals.</span>
 <span class="muRecipe">def</span> main [
   <span class="Constant">local-scope</span>
   socket:num<span class="Special"> &lt;- </span>$socket <span class="Constant">8080/port</span>
   $print <span class="Constant">[Mu socket creation returned ]</span>, socket, <span class="Constant">10/newline</span>
   session:num<span class="Special"> &lt;- </span>$accept socket
-  write-to-socket session, <span class="Constant">[HTTP/1.0 200 OK</span>
-
-<span class="Constant">OK]</span>
+  contents:&amp;:source:char, sink:&amp;:sink:char<span class="Special"> &lt;- </span>new-channel <span class="Constant">30</span>
+  sink<span class="Special"> &lt;- </span>start-running transmit-from-socket session, sink
+  buf:&amp;:buffer<span class="Special"> &lt;- </span>new-buffer <span class="Constant">30</span>
   <span class="Delimiter">{</span>
-    c:char, eof?:boolean<span class="Special"> &lt;- </span>$read-from-socket session
-    $print c
-    <span class="muControl">break-if</span> eof?
+    c:char, done?:bool, contents<span class="Special"> &lt;- </span>read contents
+    <span class="muControl">break-if</span> done?
+    buf<span class="Special"> &lt;- </span>append buf, c
     <span class="muControl">loop</span>
   <span class="Delimiter">}</span>
-  $print <span class="Constant">10/newline</span>, <span class="Constant">[Hit end of socket, closing...]</span>, <span class="Constant">10/newline</span>
-  $close-socket socket, session
+  socket-text:text<span class="Special"> &lt;- </span>buffer-to-array buf
+  $print <span class="Constant">[Done reading from socket.]</span>, <span class="Constant">10/newline</span>
+  write-to-socket session, <span class="Constant">[HTTP/1.0 200 OK</span>
+<span class="Constant">Content-type: text/plain</span>
+
+<span class="Constant">SUCCESS!</span>
+<span class="Constant">]</span>
+  $print <span class="Constant">10/newline</span>, <span class="Constant">[Wrote to and closing socket...]</span>, <span class="Constant">10/newline</span>
+  $close-socket session
+  $close-socket socket
 ]
 
 <span class="muRecipe">def</span> write-to-socket session-socket:number, s:address:array:character [
@@ -56,11 +71,33 @@ body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color
     done?:boolean<span class="Special"> &lt;- </span>greater-or-equal i, len
     <span class="muControl">break-if</span> done?
     c:character<span class="Special"> &lt;- </span>index *s, i
+    $print <span class="Constant">[writing to socket: ]</span>, i, <span class="Constant">[ ]</span>, c, <span class="Constant">10/newline</span>
     $write-to-socket session-socket, c
     i<span class="Special"> &lt;- </span>add i, <span class="Constant">1</span>
     <span class="muControl">loop</span>
   <span class="Delimiter">}</span>
 ]
+
+<span class="muRecipe">def</span> transmit-from-socket session:num, sink:&amp;:sink:char<span class="muRecipe"> -&gt; </span>sink:&amp;:sink:char [
+  <span class="Constant">local-scope</span>
+  <span class="Constant">load-ingredients</span>
+  <span class="Delimiter">{</span>
+    req:text, bytes-read:number<span class="Special"> &lt;- </span>$read-from-socket session, <span class="Constant">4096/bytes</span>
+    $print <span class="Constant">[read ]</span>, bytes-read, <span class="Constant">[ bytes from socket]</span>, <span class="Constant">10/newline</span>
+    i:number<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
+    <span class="Delimiter">{</span>
+      done?:boolean<span class="Special"> &lt;- </span>greater-or-equal i, bytes-read
+      <span class="muControl">break-if</span> done?
+      c:char<span class="Special"> &lt;- </span>index *req, i
+      end-of-request?:bool<span class="Special"> &lt;- </span>equal c, <span class="Constant">10/newline</span>
+      <span class="muControl">break-if</span> end-of-request? <span class="Comment"># To be safe, for now.</span>
+      sink<span class="Special"> &lt;- </span>write sink, c
+      i<span class="Special"> &lt;- </span>add i, <span class="Constant">1</span>
+      <span class="muControl">loop</span>
+    <span class="Delimiter">}</span>
+  <span class="Delimiter">}</span>
+  sink<span class="Special"> &lt;- </span>close sink
+]
 </pre>
 </body>
 </html>