about summary refs log tree commit diff stats
path: root/html/032array.cc.html
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-11-11 15:54:19 -0800
committerKartik K. Agaram <vc@akkartik.com>2016-11-11 15:54:19 -0800
commit6d007fda037331e7761d2a9ed3a2e435131daf7e (patch)
tree656aa7fe284b2b11c01f0389fe81f1b31025ce4e /html/032array.cc.html
parentc9f920da6e6b3e7049f078fea35e08256cae7c5b (diff)
downloadmu-6d007fda037331e7761d2a9ed3a2e435131daf7e.tar.gz
3667
Diffstat (limited to 'html/032array.cc.html')
-rw-r--r--html/032array.cc.html197
1 files changed, 150 insertions, 47 deletions
diff --git a/html/032array.cc.html b/html/032array.cc.html
index d8264b08..fce1f02d 100644
--- a/html/032array.cc.html
+++ b/html/032array.cc.html
@@ -135,23 +135,38 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span
 ]
 <span class="traceContains">+app: foo: 3 14 15 16</span>
 
-<span class="Delimiter">:(before &quot;End size_of(reagent r) Cases&quot;)</span>
+<span class="Delimiter">:(before &quot;End types_coercible Special-cases&quot;)</span>
+<span class="Normal">if</span> <span class="Delimiter">(</span>is_mu_array<span class="Delimiter">(</span>from<span class="Delimiter">)</span> &amp;&amp; is_mu_array<span class="Delimiter">(</span>to<span class="Delimiter">))</span>
+  <span class="Identifier">return</span> types_strictly_match<span class="Delimiter">(</span>array_element<span class="Delimiter">(</span>from<span class="Delimiter">.</span>type<span class="Delimiter">),</span> array_element<span class="Delimiter">(</span>to<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
+
+<span class="Delimiter">:(before &quot;End size_of(reagent r) Special-cases&quot;)</span>
 <span class="Normal">if</span> <span class="Delimiter">(</span>!r<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>atom &amp;&amp; r<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>atom &amp;&amp; r<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>value == get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;array&quot;</span><span class="Delimiter">))</span> <span class="Delimiter">{</span>
   <span class="Normal">if</span> <span class="Delimiter">(</span>!r<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">)</span> <span class="Delimiter">{</span>
     raise &lt;&lt; maybe<span class="Delimiter">(</span>current_recipe_name<span class="Delimiter">())</span> &lt;&lt; <span class="Constant">&quot;'&quot;</span> &lt;&lt; r<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;' is an array of what?</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
     <span class="Identifier">return</span> <span class="Constant">1</span><span class="Delimiter">;</span>
   <span class="Delimiter">}</span>
-  type_tree* element_type = copy_array_element<span class="Delimiter">(</span>r<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
-  <span class="Normal">int</span> result = <span class="Constant">1</span> + array_length<span class="Delimiter">(</span>r<span class="Delimiter">)</span>*size_of<span class="Delimiter">(</span>element_type<span class="Delimiter">);</span>
-  <span class="Normal">delete</span> element_type<span class="Delimiter">;</span>
-  <span class="Identifier">return</span> result<span class="Delimiter">;</span>
+  <span class="Identifier">return</span> <span class="Comment">/*</span><span class="Comment">space for length</span><span class="Comment">*/</span><span class="Constant">1</span> + array_length<span class="Delimiter">(</span>r<span class="Delimiter">)</span>*size_of<span class="Delimiter">(</span>array_element<span class="Delimiter">(</span>r<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
+<span class="Delimiter">}</span>
+
+<span class="Delimiter">:(before &quot;End size_of(type) Non-atom Special-cases&quot;)</span>
+<span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>value == get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;array&quot;</span><span class="Delimiter">))</span> <span class="Identifier">return</span> static_array_length<span class="Delimiter">(</span>type<span class="Delimiter">);</span>
+<span class="Delimiter">:(code)</span>
+<span class="Normal">int</span> static_array_length<span class="Delimiter">(</span><span class="Normal">const</span> type_tree* type<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+  <span class="Normal">if</span> <span class="Delimiter">(</span>!type<span class="Delimiter">-&gt;</span>atom &amp;&amp; type<span class="Delimiter">-&gt;</span>right &amp;&amp; !type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>atom &amp;&amp; type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right &amp;&amp; !type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>atom &amp;&amp; !type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right  <span class="Comment">// exactly 3 types</span>
+      &amp;&amp; type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left &amp;&amp; type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>atom &amp;&amp; is_integer<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>name<span class="Delimiter">))</span> <span class="Delimiter">{</span>  <span class="Comment">// third 'type' is a number</span>
+    <span class="Comment">// get size from type</span>
+    <span class="Identifier">return</span> to_integer<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>name<span class="Delimiter">);</span>
+  <span class="Delimiter">}</span>
+  cerr &lt;&lt; to_string<span class="Delimiter">(</span>type<span class="Delimiter">)</span> &lt;&lt; <span class="cSpecial">'\n'</span><span class="Delimiter">;</span>
+  assert<span class="Delimiter">(</span><span class="Constant">false</span><span class="Delimiter">);</span>
 <span class="Delimiter">}</span>
 
 <span class="Comment">//: disable the size mismatch check for arrays since the destination array</span>
 <span class="Comment">//: need not be initialized</span>
-<span class="Delimiter">:(before &quot;End size_mismatch(x) Cases&quot;)</span>
+<span class="Delimiter">:(before &quot;End size_mismatch(x) Special-cases&quot;)</span>
 <span class="Normal">if</span> <span class="Delimiter">(</span>x<span class="Delimiter">.</span>type &amp;&amp; !x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>atom &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>value == get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;array&quot;</span><span class="Delimiter">))</span> <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
 
+<span class="SalientComment">//:: arrays inside containers</span>
 <span class="Comment">//: arrays are disallowed inside containers unless their length is fixed in</span>
 <span class="Comment">//: advance</span>
 
@@ -161,6 +176,11 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span
 ]
 $error: <span class="Constant">0</span>
 
+<span class="Delimiter">:(before &quot;End insert_container Special-cases&quot;)</span>
+<span class="Normal">else</span> <span class="Normal">if</span> <span class="Delimiter">(</span>is_integer<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>name<span class="Delimiter">))</span> <span class="Delimiter">{</span>  <span class="Comment">// sometimes types will contain non-type tags, like numbers for the size of an array</span>
+  type<span class="Delimiter">-&gt;</span>value = <span class="Constant">0</span><span class="Delimiter">;</span>
+<span class="Delimiter">}</span>
+
 <span class="Delimiter">:(scenario container_disallows_dynamic_array_element)</span>
 <span class="Special">% Hide_errors = true;</span>
 <span class="muData">container</span> foo [
@@ -168,25 +188,6 @@ $error: <span class="Constant">0</span>
 ]
 <span class="traceContains">+error: container 'foo' cannot determine size of element 'x'</span>
 
-<span class="Comment">//: disable the size mismatch check for 'merge' instructions since containers</span>
-<span class="Comment">//: can contain arrays, and since we already do plenty of checking for them</span>
-<span class="Delimiter">:(before &quot;End size_mismatch(x) Cases&quot;)</span>
-<span class="Normal">if</span> <span class="Delimiter">(</span>current_call<span class="Delimiter">().</span>running_step_index &lt; SIZE<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> current_call<span class="Delimiter">().</span>running_recipe<span class="Delimiter">).</span>steps<span class="Delimiter">)</span>
-    &amp;&amp; current_instruction<span class="Delimiter">().</span>operation == MERGE<span class="Delimiter">)</span> <span class="Delimiter">{</span>
-  <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
-<span class="Delimiter">}</span>
-
-<span class="Delimiter">:(scenario merge_static_array_into_container)</span>
-<span class="muData">container</span> foo [
-  <span class="Normal">x</span>:num
-  <span class="Normal">y</span>:array:num:<span class="Constant">3</span>
-]
-<span class="muRecipe">def</span> main [
-  <span class="Constant">1</span>:array:num:<span class="Constant">3</span><span class="Special"> &lt;- </span>create-array
-  <span class="Constant">10</span>:foo<span class="Special"> &lt;- </span>merge <span class="Constant">34</span><span class="Delimiter">,</span> <span class="Constant">1</span>:array:num:<span class="Constant">3</span>
-]
-<span class="Comment"># no errors</span>
-
 <span class="Delimiter">:(before &quot;End Load Container Element Definition&quot;)</span>
 <span class="Delimiter">{</span>
   <span class="Normal">const</span> type_tree* type = info<span class="Delimiter">.</span>elements<span class="Delimiter">.</span>back<span class="Delimiter">().</span>type<span class="Delimiter">;</span>
@@ -199,13 +200,32 @@ $error: <span class="Constant">0</span>
       raise &lt;&lt; <span class="Constant">&quot;container '&quot;</span> &lt;&lt; name &lt;&lt; <span class="Constant">&quot;' doesn't specify type of array elements for '&quot;</span> &lt;&lt; info<span class="Delimiter">.</span>elements<span class="Delimiter">.</span>back<span class="Delimiter">().</span>name &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">continue</span><span class="Delimiter">;</span>
     <span class="Delimiter">}</span>
-    <span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>atom<span class="Delimiter">)</span> <span class="Delimiter">{</span>  <span class="Comment">// array has no length</span>
+    <span class="Normal">if</span> <span class="Delimiter">(</span>!type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right || !is_integer<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>name<span class="Delimiter">))</span> <span class="Delimiter">{</span>  <span class="Comment">// array has no length</span>
       raise &lt;&lt; <span class="Constant">&quot;container '&quot;</span> &lt;&lt; name &lt;&lt; <span class="Constant">&quot;' cannot determine size of element '&quot;</span> &lt;&lt; info<span class="Delimiter">.</span>elements<span class="Delimiter">.</span>back<span class="Delimiter">().</span>name &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">continue</span><span class="Delimiter">;</span>
     <span class="Delimiter">}</span>
   <span class="Delimiter">}</span>
 <span class="Delimiter">}</span>
 
+<span class="Comment">//: disable the size mismatch check for 'merge' instructions since containers</span>
+<span class="Comment">//: can contain arrays, and since we already do plenty of checking for them</span>
+<span class="Delimiter">:(before &quot;End size_mismatch(x) Special-cases&quot;)</span>
+<span class="Normal">if</span> <span class="Delimiter">(</span>current_call<span class="Delimiter">().</span>running_step_index &lt; SIZE<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> current_call<span class="Delimiter">().</span>running_recipe<span class="Delimiter">).</span>steps<span class="Delimiter">)</span>
+    &amp;&amp; current_instruction<span class="Delimiter">().</span>operation == MERGE<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+  <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
+<span class="Delimiter">}</span>
+
+<span class="Delimiter">:(scenario merge_static_array_into_container)</span>
+<span class="muData">container</span> foo [
+  <span class="Normal">x</span>:num
+  <span class="Normal">y</span>:array:num:<span class="Constant">3</span>
+]
+<span class="muRecipe">def</span> main [
+  <span class="Constant">1</span>:array:num:<span class="Constant">3</span><span class="Special"> &lt;- </span>create-array
+  <span class="Constant">10</span>:foo<span class="Special"> &lt;- </span>merge <span class="Constant">34</span><span class="Delimiter">,</span> <span class="Constant">1</span>:array:num:<span class="Constant">3</span>
+]
+<span class="Comment"># no errors</span>
+
 <span class="Delimiter">:(scenario code_inside_container)</span>
 <span class="Special">% Hide_errors = true;</span>
 <span class="muData">container</span> card [
@@ -217,6 +237,75 @@ $error: <span class="Constant">0</span>
 ]
 <span class="Comment"># shouldn't die</span>
 
+<span class="SalientComment">//:: containers inside arrays</span>
+<span class="Comment">//: make sure we compute container sizes inside arrays</span>
+
+<span class="Delimiter">:(before &quot;End compute_container_sizes Non-atom Special-cases&quot;)</span>
+<span class="Normal">else</span> <span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>name == <span class="Constant">&quot;array&quot;</span><span class="Delimiter">)</span>
+  compute_container_sizes<span class="Delimiter">(</span>array_element<span class="Delimiter">(</span>type<span class="Delimiter">),</span> pending_metadata<span class="Delimiter">,</span> location_for_error_messages<span class="Delimiter">);</span>
+
+<span class="Delimiter">:(before &quot;End Unit Tests&quot;)</span>
+<span class="Normal">void</span> test_container_sizes_from_array<span class="Delimiter">()</span> <span class="Delimiter">{</span>
+  <span class="Comment">// a container we don't have the size for</span>
+  reagent container<span class="Delimiter">(</span><span class="Constant">&quot;x:point&quot;</span><span class="Delimiter">);</span>
+  CHECK<span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
+  <span class="Comment">// scanning an array of the container precomputes the size of the container</span>
+  reagent r<span class="Delimiter">(</span><span class="Constant">&quot;x:array:point&quot;</span><span class="Delimiter">);</span>
+  compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">,</span> <span class="Constant">&quot;&quot;</span><span class="Delimiter">);</span>
+  CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
+  CHECK_EQ<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">).</span>size<span class="Delimiter">,</span> <span class="Constant">2</span><span class="Delimiter">);</span>
+<span class="Delimiter">}</span>
+
+<span class="Normal">void</span> test_container_sizes_from_address_to_array<span class="Delimiter">()</span> <span class="Delimiter">{</span>
+  <span class="Comment">// a container we don't have the size for</span>
+  reagent container<span class="Delimiter">(</span><span class="Constant">&quot;x:point&quot;</span><span class="Delimiter">);</span>
+  CHECK<span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
+  <span class="Comment">// scanning an address to an array of the container precomputes the size of the container</span>
+  reagent r<span class="Delimiter">(</span><span class="Constant">&quot;x:address:array:point&quot;</span><span class="Delimiter">);</span>
+  compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">,</span> <span class="Constant">&quot;&quot;</span><span class="Delimiter">);</span>
+  CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
+  CHECK_EQ<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">).</span>size<span class="Delimiter">,</span> <span class="Constant">2</span><span class="Delimiter">);</span>
+<span class="Delimiter">}</span>
+
+<span class="Normal">void</span> test_container_sizes_from_static_array<span class="Delimiter">()</span> <span class="Delimiter">{</span>
+  <span class="Comment">// a container we don't have the size for</span>
+  reagent container<span class="Delimiter">(</span><span class="Constant">&quot;x:point&quot;</span><span class="Delimiter">);</span>
+  <span class="Normal">int</span> old_size = SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">);</span>
+  <span class="Comment">// scanning an address to an array of the container precomputes the size of the container</span>
+  reagent r<span class="Delimiter">(</span><span class="Constant">&quot;x:array:point:10&quot;</span><span class="Delimiter">);</span>
+  compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">,</span> <span class="Constant">&quot;&quot;</span><span class="Delimiter">);</span>
+  CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
+  CHECK_EQ<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">).</span>size<span class="Delimiter">,</span> <span class="Constant">2</span><span class="Delimiter">);</span>
+  <span class="Comment">// no non-container types precomputed</span>
+  CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
+<span class="Delimiter">}</span>
+
+<span class="Normal">void</span> test_container_sizes_from_address_to_static_array<span class="Delimiter">()</span> <span class="Delimiter">{</span>
+  <span class="Comment">// a container we don't have the size for</span>
+  reagent container<span class="Delimiter">(</span><span class="Constant">&quot;x:point&quot;</span><span class="Delimiter">);</span>
+  <span class="Normal">int</span> old_size = SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">);</span>
+  <span class="Comment">// scanning an address to an array of the container precomputes the size of the container</span>
+  reagent r<span class="Delimiter">(</span><span class="Constant">&quot;x:address:array:point:10&quot;</span><span class="Delimiter">);</span>
+  compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">,</span> <span class="Constant">&quot;&quot;</span><span class="Delimiter">);</span>
+  CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
+  CHECK_EQ<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">).</span>size<span class="Delimiter">,</span> <span class="Constant">2</span><span class="Delimiter">);</span>
+  <span class="Comment">// no non-container types precomputed</span>
+  CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
+<span class="Delimiter">}</span>
+
+<span class="Normal">void</span> test_container_sizes_from_repeated_address_and_array_types<span class="Delimiter">()</span> <span class="Delimiter">{</span>
+  <span class="Comment">// a container we don't have the size for</span>
+  reagent container<span class="Delimiter">(</span><span class="Constant">&quot;x:point&quot;</span><span class="Delimiter">);</span>
+  <span class="Normal">int</span> old_size = SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">);</span>
+  <span class="Comment">// scanning repeated address and array types modifying the container precomputes the size of the container</span>
+  reagent r<span class="Delimiter">(</span><span class="Constant">&quot;x:address:array:address:array:point:10&quot;</span><span class="Delimiter">);</span>
+  compute_container_sizes<span class="Delimiter">(</span>r<span class="Delimiter">,</span> <span class="Constant">&quot;&quot;</span><span class="Delimiter">);</span>
+  CHECK<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
+  CHECK_EQ<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> container<span class="Delimiter">.</span>type<span class="Delimiter">).</span>size<span class="Delimiter">,</span> <span class="Constant">2</span><span class="Delimiter">);</span>
+  <span class="Comment">// no non-container types precomputed</span>
+  CHECK_EQ<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">)</span>-old_size<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">);</span>
+<span class="Delimiter">}</span>
+
 <span class="SalientComment">//:: To access elements of an array, use 'index'</span>
 
 <span class="Delimiter">:(scenario index)</span>
@@ -275,7 +364,7 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span
   <span class="Normal">if</span> <span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Identifier">break</span><span class="Delimiter">;</span>
   reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> product = 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="Comment">// Update INDEX product in Check</span>
-  reagent element<span class="Delimiter">;</span>
+  reagent<span class="Comment">/*</span><span class="Comment">local</span><span class="Comment">*/</span> element<span class="Delimiter">;</span>
   element<span class="Delimiter">.</span>type = copy_array_element<span class="Delimiter">(</span>base<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
   <span class="Normal">if</span> <span class="Delimiter">(</span>!types_coercible<span class="Delimiter">(</span>product<span class="Delimiter">,</span> element<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;'index' on '&quot;</span> &lt;&lt; base<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;' can't be saved in '&quot;</span> &lt;&lt; product<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;'; type should be '&quot;</span> &lt;&lt; names_to_string_without_quotes<span class="Delimiter">(</span>element<span class="Delimiter">.</span>type<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>
@@ -300,13 +389,11 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span
     raise &lt;&lt; maybe<span class="Delimiter">(</span>current_recipe_name<span class="Delimiter">())</span> &lt;&lt; <span class="Constant">&quot;invalid index &quot;</span> &lt;&lt; no_scientific<span class="Delimiter">(</span>index_val<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">))</span> &lt;&lt; <span class="Constant">&quot; in '&quot;</span> &lt;&lt; to_original_string<span class="Delimiter">(</span>current_instruction<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>
-  type_tree* element_type = copy_array_element<span class="Delimiter">(</span>base<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
-  <span class="Normal">int</span> src = base_address + <span class="Constant">1</span> + index_val<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span>*size_of<span class="Delimiter">(</span>element_type<span class="Delimiter">);</span>
-  trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">&quot;run&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;address to copy is &quot;</span> &lt;&lt; src &lt;&lt; end<span class="Delimiter">();</span>
-  trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">&quot;run&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;its type is &quot;</span> &lt;&lt; to_string<span class="Delimiter">(</span>element_type<span class="Delimiter">)</span> &lt;&lt; end<span class="Delimiter">();</span>
-  reagent element<span class="Delimiter">;</span>
-  element<span class="Delimiter">.</span>set_value<span class="Delimiter">(</span>src<span class="Delimiter">);</span>
-  element<span class="Delimiter">.</span>type = element_type<span class="Delimiter">;</span>
+  reagent<span class="Comment">/*</span><span class="Comment">local</span><span class="Comment">*/</span> element<span class="Delimiter">;</span>
+  element<span class="Delimiter">.</span>type = copy_array_element<span class="Delimiter">(</span>base<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
+  element<span class="Delimiter">.</span>set_value<span class="Delimiter">(</span>base_address + <span class="Comment">/*</span><span class="Comment">skip length</span><span class="Comment">*/</span><span class="Constant">1</span> + index_val<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span>*size_of<span class="Delimiter">(</span>element<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
+  trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">&quot;run&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;address to copy is &quot;</span> &lt;&lt; element<span class="Delimiter">.</span>value &lt;&lt; end<span class="Delimiter">();</span>
+  trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">&quot;run&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;its type is &quot;</span> &lt;&lt; to_string<span class="Delimiter">(</span>element<span class="Delimiter">.</span>type<span class="Delimiter">)</span> &lt;&lt; end<span class="Delimiter">();</span>
   <span class="Comment">// Read element</span>
   products<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>read_memory<span class="Delimiter">(</span>element<span class="Delimiter">));</span>
   <span class="Identifier">break</span><span class="Delimiter">;</span>
@@ -314,24 +401,38 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span
 
 <span class="Delimiter">:(code)</span>
 type_tree* copy_array_element<span class="Delimiter">(</span><span class="Normal">const</span> type_tree* type<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+  <span class="Identifier">return</span> <span class="Normal">new</span> type_tree<span class="Delimiter">(</span>*array_element<span class="Delimiter">(</span>type<span class="Delimiter">));</span>
+<span class="Delimiter">}</span>
+
+type_tree* array_element<span class="Delimiter">(</span><span class="Normal">const</span> type_tree* type<span class="Delimiter">)</span> <span class="Delimiter">{</span>
   assert<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">);</span>
-  <span class="Comment">// hack: don't require parens for either array:num:3 array:address:num</span>
-  <span class="Normal">if</span> <span class="Delimiter">(</span>!type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>atom &amp;&amp; type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right &amp;&amp; type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>atom &amp;&amp; is_integer<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>name<span class="Delimiter">))</span>
-    <span class="Identifier">return</span> <span class="Normal">new</span> type_tree<span class="Delimiter">(</span>*type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left<span class="Delimiter">);</span>
-  <span class="Identifier">return</span> <span class="Normal">new</span> type_tree<span class="Delimiter">(</span>*type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">);</span>
+  <span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>atom<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+    <span class="Identifier">return</span> type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">;</span>
+  <span class="Delimiter">}</span>
+  <span class="Normal">else</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">)</span> <span class="Delimiter">{</span>
+    <span class="Identifier">return</span> type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left<span class="Delimiter">;</span>
+  <span class="Delimiter">}</span>
+  <span class="Comment">// hack: support array:num:3 without requiring extra parens</span>
+  <span class="Normal">else</span> <span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left &amp;&amp; type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>atom &amp;&amp; is_integer<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>name<span class="Delimiter">))</span> <span class="Delimiter">{</span>
+    assert<span class="Delimiter">(</span>!type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">);</span>
+    <span class="Identifier">return</span> type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left<span class="Delimiter">;</span>
+  <span class="Delimiter">}</span>
+  <span class="Identifier">return</span> type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">;</span>
 <span class="Delimiter">}</span>
 
 <span class="Normal">int</span> array_length<span class="Delimiter">(</span><span class="Normal">const</span> reagent&amp; x<span class="Delimiter">)</span> <span class="Delimiter">{</span>
-  <span class="Normal">if</span> <span class="Delimiter">(</span>!x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>atom &amp;&amp; !x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>atom &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>atom  <span class="Comment">// exactly 3 types</span>
-      &amp;&amp; is_integer<span class="Delimiter">(</span>x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>name<span class="Delimiter">))</span> <span class="Delimiter">{</span>  <span class="Comment">// third 'type' is a number</span>
+  <span class="Comment">// x should already be canonized.</span>
+  <span class="Comment">// hack: look for length in type</span>
+  <span class="Normal">if</span> <span class="Delimiter">(</span>!x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>atom &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right &amp;&amp; !x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>atom &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right &amp;&amp; !x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>atom &amp;&amp; !x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right  <span class="Comment">// exactly 3 types</span>
+      &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>atom &amp;&amp; is_integer<span class="Delimiter">(</span>x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>name<span class="Delimiter">))</span> <span class="Delimiter">{</span>  <span class="Comment">// third 'type' is a number</span>
     <span class="Comment">// get size from type</span>
-    <span class="Identifier">return</span> to_integer<span class="Delimiter">(</span>x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>name<span class="Delimiter">);</span>
+    <span class="Identifier">return</span> to_integer<span class="Delimiter">(</span>x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>name<span class="Delimiter">);</span>
   <span class="Delimiter">}</span>
   <span class="Comment">// this should never happen at transform time</span>
-  <span class="Comment">// x should already be canonized.</span>
   <span class="Identifier">return</span> get_or_insert<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> x<span class="Delimiter">.</span>value<span class="Delimiter">);</span>
 <span class="Delimiter">}</span>
 
+<span class="Delimiter">:(before &quot;End Unit Tests&quot;)</span>
 <span class="Normal">void</span> test_array_length_compound<span class="Delimiter">()</span> <span class="Delimiter">{</span>
   put<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> <span class="Constant">1</span><span class="Delimiter">,</span> <span class="Constant">3</span><span class="Delimiter">);</span>
   put<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> <span class="Constant">2</span><span class="Delimiter">,</span> <span class="Constant">14</span><span class="Delimiter">);</span>
@@ -342,6 +443,11 @@ type_tree* copy_array_element<span class="Delimiter">(</span><span class="Normal
   CHECK_EQ<span class="Delimiter">(</span>array_length<span class="Delimiter">(</span>x<span class="Delimiter">),</span> <span class="Constant">3</span><span class="Delimiter">);</span>
 <span class="Delimiter">}</span>
 
+<span class="Normal">void</span> test_array_length_static<span class="Delimiter">()</span> <span class="Delimiter">{</span>
+  reagent x<span class="Delimiter">(</span><span class="Constant">&quot;1:array:num:3&quot;</span><span class="Delimiter">);</span>
+  CHECK_EQ<span class="Delimiter">(</span>array_length<span class="Delimiter">(</span>x<span class="Delimiter">),</span> <span class="Constant">3</span><span class="Delimiter">);</span>
+<span class="Delimiter">}</span>
+
 <span class="Delimiter">:(scenario index_truncates)</span>
 <span class="muRecipe">def</span> main [
   <span class="Constant">1</span>:array:num:<span class="Constant">3</span><span class="Special"> &lt;- </span>create-array
@@ -443,7 +549,7 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span
   <span class="Delimiter">}</span>
   reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> value = inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">2</span><span class="Delimiter">);</span>
   <span class="Comment">// Update PUT_INDEX value in Check</span>
-  reagent element<span class="Delimiter">;</span>
+  reagent<span class="Comment">/*</span><span class="Comment">local</span><span class="Comment">*/</span> element<span class="Delimiter">;</span>
   element<span class="Delimiter">.</span>type = copy_array_element<span class="Delimiter">(</span>base<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
   <span class="Normal">if</span> <span class="Delimiter">(</span>!types_coercible<span class="Delimiter">(</span>element<span class="Delimiter">,</span> value<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;'put-index &quot;</span> &lt;&lt; base<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;, &quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>original_string &lt;&lt; <span class="Constant">&quot;' should store &quot;</span> &lt;&lt; names_to_string_without_quotes<span class="Delimiter">(</span>element<span class="Delimiter">.</span>type<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot; but '&quot;</span> &lt;&lt; value<span class="Delimiter">.</span>name &lt;&lt; <span class="Constant">&quot;' has type &quot;</span> &lt;&lt; names_to_string_without_quotes<span class="Delimiter">(</span>value<span class="Delimiter">.</span>type<span class="Delimiter">)</span> &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span>
@@ -473,10 +579,7 @@ put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span
     raise &lt;&lt; maybe<span class="Delimiter">(</span>current_recipe_name<span class="Delimiter">())</span> &lt;&lt; <span class="Constant">&quot;invalid index &quot;</span> &lt;&lt; no_scientific<span class="Delimiter">(</span>index_val<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">))</span> &lt;&lt; <span class="Constant">&quot; in '&quot;</span> &lt;&lt; to_original_string<span class="Delimiter">(</span>current_instruction<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>
-  reagent element<span class="Delimiter">;</span>
-  element<span class="Delimiter">.</span>type = copy_array_element<span class="Delimiter">(</span>base<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
-  <span class="Normal">int</span> address = base_address + <span class="Constant">1</span> + index_val<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span>*size_of<span class="Delimiter">(</span>element<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
-  element<span class="Delimiter">.</span>set_value<span class="Delimiter">(</span>address<span class="Delimiter">);</span>
+  <span class="Normal">int</span> address = base_address + <span class="Comment">/*</span><span class="Comment">skip length</span><span class="Comment">*/</span><span class="Constant">1</span> + index_val<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span>*size_of<span class="Delimiter">(</span>array_element<span class="Delimiter">(</span>base<span class="Delimiter">.</span>type<span class="Delimiter">));</span>
   trace<span class="Delimiter">(</span><span class="Constant">9998</span><span class="Delimiter">,</span> <span class="Constant">&quot;run&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;address to copy to is &quot;</span> &lt;&lt; address &lt;&lt; end<span class="Delimiter">();</span>
   <span class="Comment">// optimization: directly write the element rather than updating 'product'</span>
   <span class="Comment">// and writing the entire array</span>