about summary refs log tree commit diff stats
path: root/html/030container.cc.html
blob: 1ddba97ec460bb3d4812ac708b81850039502828 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - mu-init-test.subx</title>
<meta name="Generator" content="Vim/8.1">
<meta name="plugin-version" content="vim8.1_v1">
<meta name="syntax" content="none">
<meta name="settings" content="number_lines,use_css,pre_wrap,no_foldcolumn,expand_tabs,line_ids,prevent_copy=">
<meta name="colorscheme" content="minimal-light">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #c6c6c6; }
body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; }
a { color:inherit; }
* { font-size:12pt; font-size: 1em; }
.subxComment { color: #005faf; }
.LineNr { }
.SpecialChar { color: #d70000; }
.subxS1Comment { color: #0000af; }
.subxFunction { color: #af5f00; text-decoration: underline; }
.Constant { color: #008787; }
-->
</style>

<script type='text/javascript'>
<!--

/* function to open any folds containing a jumped-to line before jumping to it */
function JumpToLine()
{
  var lineNum;
  lineNum = window.location.hash;
  lineNum = lineNum.substr(1); /* strip off '#' */

  if (lineNum.indexOf('L') == -1) {
    lineNum = 'L'+lineNum;
  }
  var lineElem = document.getElementById(lineNum);
  /* Always jump to new location even if the line was hidden inside a fold, or
   * we corrected the raw number to a line ID.
   */
  if (lineElem) {
    lineElem.scrollIntoView(true);
  }
  return true;
}
if ('onhashchange' in window) {
  window.onhashchange = JumpToLine;
}

-->
</script>
</head>
<body onload='JumpToLine();'>
<a href='https://github.com/akkartik/mu/blob/master/mu-init-test.subx'>https://github.com/akkartik/mu/blob/master/mu-init-test.subx</a>
<pre id='vimCodeElement'>
<span id="L1" class="LineNr"> 1 </span><span class="subxComment"># Just a test stub for mu-init.subx</span>
<span id="L2" class="LineNr"> 2 </span><span class="subxComment">#</span>
<span id="L3" class="LineNr"> 3 </span><span class="subxComment"># Try it out like this:</span>
<span id="L4" class="LineNr"> 4 </span><span class="subxComment">#   $ ./translate_subx init.linux [0-9]*.subx mu-init.subx mu-init-test.subx</span>
<span id="L5" class="LineNr"> 5 </span><span class="subxComment">#   $ ./a.elf  # should run all tests</span>
<span id="L6" class="LineNr"> 6 </span>
<span id="L7" class="LineNr"> 7 </span><span class="subxFunction">main</span>:  <span class="subxComment"># args: (addr array (addr array byte)) -&gt; result/ebx: int</span>
<span id="L8" class="LineNr"> 8 </span>    <span class="subxS1Comment"># . prologue</span>
<span id="L9" class="LineNr"> 9 </span>    55/push-ebp
<span id="L10" class="LineNr">10 </span>    89/&lt;- %ebp 4/r32/esp
<span id="L11" class="LineNr">11 </span>    <span class="subxS1Comment"># . s
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - 030container.cc</title>
<meta name="Generator" content="Vim/7.4">
<meta name="plugin-version" content="vim7.4_v2">
<meta name="syntax" content="cpp">
<meta name="settings" content="use_css,pre_wrap,no_foldcolumn,expand_tabs,prevent_copy=">
<meta name="colorscheme" content="minimal">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color: #080808; }
* { font-size: 12pt; font-size: 1em; }
.Constant { color: #00a0a0; }
.traceAbsent { color: #c00000; }
.cSpecial { color: #008000; }
.traceContains { color: #008000; }
.SalientComment { color: #00ffff; }
.Comment { color: #9090ff; }
.Delimiter { color: #800080; }
.Special { color: #c00000; }
.Identifier { color: #fcb165; }
.Normal { color: #eeeeee; background-color: #080808; padding-bottom: 1px; }
-->
</style>

<script type='text/javascript'>
<!--

-->
</script>
</head>
<body>
<pre id='vimCodeElement'>
<span class="Comment">//: Containers contain a fixed number of elements of different types.</span>

<span class="Delimiter">:(before &quot;End Mu Types Initialization&quot;)</span>
<span class="Comment">//: We'll use this container as a running example, with two number elements.</span>
type_ordinal point = put<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;point&quot;</span><span class="Delimiter">,</span> Next_type_ordinal++<span class="Delimiter">);</span>
get_or_insert<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> point<span class="Delimiter">);</span>  <span class="Comment">// initialize</span>
get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> point<span class="Delimiter">).</span>kind = CONTAINER<span class="Delimiter">;</span>
get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> point<span class="Delimiter">).</span>name = <span class="Constant">&quot;point&quot;</span><span class="Delimiter">;</span>
get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> point<span class="Delimiter">).</span>elements<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>reagent<span class="Delimiter">(</span><span class="Constant">&quot;x:number&quot;</span><span class="Delimiter">));</span>
get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> point<span class="Delimiter">).</span>elements<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>reagent<span class="Delimiter">(</span><span class="Constant">&quot;y:number&quot;</span><span class="Delimiter">));</span>

<span class="Comment">//: Containers can be copied around with a single instruction just like</span>
<span class="Comment">//: numbers, no matter how large they are.</span>

<span class="Comment">//: Tests in this layer often explicitly set up memory before reading it as a</span>
<span class="Comment">//: container. Don't do this in general. I'm tagging exceptions with /raw to</span>
<span class="Comment">//: avoid errors.</span>
<span class="Delimiter">:(scenario copy_multiple_locations)</span>
def main [
  <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>
  <span class="Constant">2</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">3</span>:point<span class="Special"> &lt;- </span>copy <span class="Constant">1</span>:point/unsafe
]
<span class="traceContains">+mem: storing 34 in location 3</span>
<span class="traceContains">+mem: storing 35 in location 4</span>

<span class="Comment">//: trying to copy to a differently-typed destination will fail</span>
<span class="Delimiter">:(scenario copy_checks_size)</span>
<span class="Special">% Hide_errors = true;</span>
def main [
  <span class="Constant">2</span>:point<span class="Special"> &lt;- </span>copy <span class="Constant">1</span>:number
]
<span class="traceContains">+error: main: can't copy '1:number' to '2:point'; types don't match</span>

<span class="Delimiter">:(before &quot;End Mu Types Initialization&quot;)</span>
<span class="Comment">// A more complex container, containing another container as one of its</span>
<span class="Comment">// elements.</span>
type_ordinal point_number = put<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;point-number&quot;</span><span class="Delimiter">,</span> Next_type_ordinal++<span class="Delimiter">);</span>
get_or_insert<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> point_number<span class="Delimiter">);</span>  <span class="Comment">// initialize</span>
get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> point_number<span class="Delimiter">).</span>kind = CONTAINER<span class="Delimiter">;</span>
get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> point_number<span class="Delimiter">).</span>name = <span class="Constant">&quot;point-number&quot;</span><span class="Delimiter">;</span>
get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> point_number<span class="Delimiter">).</span>elements<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>reagent<span class="Delimiter">(</span><span class="Constant">&quot;xy:point&quot;</span><span class="Delimiter">));</span>
get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> point_number<span class="Delimiter">).</span>elements<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>reagent<span class="Delimiter">(</span><span class="Constant">&quot;z:number&quot;</span><span class="Delimiter">));</span>

<span class="Delimiter">:(scenario copy_handles_nested_container_elements)</span>
def main [
  <span class="Constant">12</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>
  <span class="Constant">13</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">14</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">36</span>
  <span class="Constant">15</span>:point-number<span class="Special"> &lt;- </span>copy <span class="Constant">12</span>:point-number/unsafe
]
<span class="traceContains">+mem: storing 36 in location 17</span>

<span class="Comment">//: products of recipes can include containers</span>
<span class="Delimiter">:(scenario return_container)</span>
def main [
  <span class="Constant">3</span>:point<span class="Special"> &lt;- </span>f <span class="Constant">2</span>
]
def f [
  <span class="Constant">12</span>:number<span class="Special"> &lt;- </span>next-ingredient
  <span class="Constant">13</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Identifier">return</span> <span class="Constant">12</span>:point/<span class="Special">raw</span>
]
<span class="traceContains">+run: result 0 is [2, 35]</span>
<span class="traceContains">+mem: storing 2 in location 3</span>
<span class="traceContains">+mem: storing 35 in location 4</span>

<span class="Comment">//: Containers can be checked for equality with a single instruction just like</span>
<span class="Comment">//: numbers, no matter how large they are.</span>

<span class="Delimiter">:(scenario compare_multiple_locations)</span>
def main [
  <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>  <span class="Comment"># first</span>
  <span class="Constant">2</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">36</span>
  <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>  <span class="Comment"># second</span>
  <span class="Constant">5</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">6</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">36</span>
  <span class="Constant">7</span>:boolean<span class="Special"> &lt;- </span>equal <span class="Constant">1</span>:point-number/<span class="Special">raw</span><span class="Delimiter">,</span> <span class="Constant">4</span>:point-number/unsafe
]
<span class="traceContains">+mem: storing 1 in location 7</span>

<span class="Delimiter">:(scenario compare_multiple_locations_2)</span>
def main [
  <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>  <span class="Comment"># first</span>
  <span class="Constant">2</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">36</span>
  <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>  <span class="Comment"># second</span>
  <span class="Constant">5</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">6</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">37</span>  <span class="Comment"># different</span>
  <span class="Constant">7</span>:boolean<span class="Special"> &lt;- </span>equal <span class="Constant">1</span>:point-number/<span class="Special">raw</span><span class="Delimiter">,</span> <span class="Constant">4</span>:point-number/unsafe
]
<span class="traceContains">+mem: storing 0 in location 7</span>

<span class="Comment">//: Can't put this in type_info because later layers will add support for more</span>
<span class="Comment">//: complex type trees where metadata depends on *combinations* of types.</span>
<span class="Delimiter">:(before &quot;struct reagent&quot;)</span>
<span class="Normal">struct</span> container_metadata <span class="Delimiter">{</span>
  <span class="Normal">int</span> size<span class="Delimiter">;</span>
  vector&lt;<span class="Normal">int</span>&gt; offset<span class="Delimiter">;</span>  <span class="Comment">// not used by exclusive containers</span>
  <span class="Comment">// End container_metadata Fields</span>
  container_metadata<span class="Delimiter">()</span> :size<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Comment">// End container_metadata Constructor</span>
  <span class="Delimiter">}</span>
<span class="Delimiter">};</span>
<span class="Delimiter">:(before &quot;End reagent Fields&quot;)</span>
container_metadata metadata<span class="Delimiter">;</span>  <span class="Comment">// can't be a pointer into Container_metadata because we keep changing the base storage when we save/restore snapshots</span>
<span class="Delimiter">:(before &quot;End reagent Copy Operator&quot;)</span>
metadata = other<span class="Delimiter">.</span>metadata<span class="Delimiter">;</span>
<span class="Delimiter">:(before &quot;End reagent Copy Constructor&quot;)</span>
metadata = other<span class="Delimiter">.</span>metadata<span class="Delimiter">;</span>

<span class="Delimiter">:(before &quot;End Globals&quot;)</span>
<span class="Comment">// todo: switch to map after figuring out how to consistently compare type trees</span>
vector&lt;pair&lt;type_tree*<span class="Delimiter">,</span> container_metadata&gt; &gt; Container_metadata<span class="Delimiter">,</span> Container_metadata_snapshot<span class="Delimiter">;</span>
<span class="Delimiter">:(before &quot;End save_snapshots&quot;)</span>
Container_metadata_snapshot = Container_metadata<span class="Delimiter">;</span>
<span class="Delimiter">:(before &quot;End restore_snapshots&quot;)</span>
restore_container_metadata<span class="Delimiter">();</span>
<span class="Delimiter">:(before &quot;End One-time Setup&quot;)</span>
atexit<span class="Delimiter">(</span>clear_container_metadata<span class="Delimiter">);</span>
<span class="Delimiter">:(code)</span>
<span class="Comment">// invariant: Container_metadata always contains a superset of Container_metadata_snapshot</span>
<span class="Normal">void</span> restore_container_metadata<span class="Delimiter">()</span> <span class="Delimiter">{</span>
  <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>Container_metadata<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    assert<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>first<span class="Delimiter">);</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>i &lt; SIZE<span class="Delimiter">(</span>Container_metadata_snapshot<span class="Delimiter">))</span> <span class="Delimiter">{</span>
      assert<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>first == Container_metadata_snapshot<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>first<span class="Delimiter">);</span>
      <span class="Identifier">continue</span><span class="Delimiter">;</span>
    <span class="Delimiter">}</span>
    <span class="Normal">delete</span> Container_metadata<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>first<span class="Delimiter">;</span>
    Container_metadata<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>first = <span class="Constant">NULL</span><span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  Container_metadata<span class="Delimiter">.</span>resize<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>Container_metadata_snapshot<span class="Delimiter">));</span>
<span class="Delimiter">}</span>
<span class="Normal">void</span> clear_container_metadata<span class="Delimiter">()</span> <span class="Delimiter">{</span>
  Container_metadata_snapshot<span class="Delimiter">.</span>clear<span class="Delimiter">();</span>
  <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>Container_metadata<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Normal">delete</span> Container_metadata<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>first<span class="Delimiter">;</span>
    Container_metadata<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>first = <span class="Constant">NULL</span><span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  Container_metadata<span class="Delimiter">.</span>clear<span class="Delimiter">();</span>
<span class="Delimiter">}</span>

<span class="Comment">//: do no work in size_of, simply lookup Container_metadata</span>

<span class="Delimiter">:(before &quot;End size_of(reagent r) Cases&quot;)</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>r<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>size<span class="Delimiter">)</span> <span class="Identifier">return</span> r<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>size<span class="Delimiter">;</span>

<span class="Delimiter">:(before &quot;End size_of(type) Cases&quot;)</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>value == -<span class="Constant">1</span><span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">1</span><span class="Delimiter">;</span>  <span class="Comment">// error value, but we'll raise it elsewhere</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>value == <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
  assert<span class="Delimiter">(</span>!type<span class="Delimiter">-&gt;</span>left &amp;&amp; !type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">);</span>
  <span class="Identifier">return</span> <span class="Constant">1</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">))</span> <span class="Delimiter">{</span>
  raise &lt;&lt; <span class="Constant">&quot;no such type &quot;</span> &lt;&lt; type<span class="Delimiter">-&gt;</span>value &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span>
  <span class="Identifier">return</span> <span class="Constant">0</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>
type_info t = get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">);</span>
<span class="Normal">if</span> <span class="Delimiter">(</span>t<span class="Delimiter">.</span>kind == CONTAINER<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Comment">// Compute size_of Container</span>
  <span class="Identifier">return</span> get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> type<span class="Delimiter">).</span>size<span class="Delimiter">;</span>
<span class="Delimiter">}</span>

<span class="Comment">//: precompute Container_metadata before we need size_of</span>
<span class="Comment">//: also store a copy in each reagent in each instruction in each recipe</span>

<span class="Delimiter">:(after &quot;Begin Instruction Modifying Transforms&quot;)  // needs to happen before transform_names, therefore after &quot;End Type Modifying Transforms&quot; below</span>
<span class="Delimiter">Transform.push_back(compute_container_sizes)</span><span class="Delimiter">;</span>
<span class="Delimiter">:(code)</span>
<span class="Normal">void</span> compute_container_sizes<span class="Delimiter">(</span>recipe_ordinal r<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  recipe&amp; caller = get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">);</span>
  <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>
    instruction&amp; inst = caller<span class="Delimiter">.</span>steps<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span>
    <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>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span>
      compute_container_sizes<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">));</span>
    <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>inst<span class="Delimiter">.</span>products<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span>
      compute_container_sizes<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">));</span>
  <span class="Delimiter">}</span>
<span class="Delimiter">}</span>

<span class="Normal">void</span> compute_container_sizes<span class="Delimiter">(</span>reagent&amp; r<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>is_literal<span class="Delimiter">(</span>r<span class="Delimiter">)</span> || is_dummy<span class="Delimiter">(</span>r<span class="Delimiter">))</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
  reagent rcopy = r<span class="Delimiter">;</span>
  <span class="Comment">// Compute Container Size(reagent rcopy)</span>
  set&lt;type_ordinal&gt; pending_metadata<span class="Delimiter">;</span>
  compute_container_sizes<span class="Delimiter">(</span>rcopy<span class="Delimiter">.</span>type<span class="Delimiter">,</span> pending_metadata<span class="Delimiter">);</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> rcopy<span class="Delimiter">.</span>type<span class="Delimiter">))</span>
    r<span class="Delimiter">.</span>metadata = get<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> rcopy<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
<span class="Delimiter">}</span>

<span class="Normal">void</span> compute_container_sizes<span class="Delimiter">(</span><span class="Normal">const</span> type_tree* type<span class="Delimiter">,</span> set&lt;type_ordinal&gt;&amp; pending_metadata<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!type<span class="Delimiter">)</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>pending_metadata<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">))</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">)</span> pending_metadata<span class="Delimiter">.</span>insert<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">);</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Container_metadata<span class="Delimiter">,</span> type<span class="Delimiter">))</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>left<span class="Delimiter">)</span> compute_container_sizes<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>left<span class="Delimiter">,</span> pending_metadata<span class="Delimiter">);</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">)</span> compute_container_sizes<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">,</span> pending_metadata<span class="Delimiter">);</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">))</span> <span class="Identifier">return</span><span class="Delimiter">;</span>  <span class="Comment">// error raised elsewhere</span>
  type_info&amp; info = get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">);</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>info<span class="Delimiter">.</span>kind == CONTAINER<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    container_metadata metadata<span class="Delimiter">;</span>
    <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>info<span class="Delimiter">.</span>elements<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
      reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> element = info<span class="Delimiter">.</span>elements<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span>
      <span class="Comment">// Compute Container Size(element)</span>
      compute_container_sizes<span class="Delimiter">(</span>element<span class="Delimiter">.</span>type<span class="Delimiter">,</span> pending_metadata<span class="Delimiter">);</span>
      metadata<span class="Delimiter">.</span>offset<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>metadata<span class="Delimiter">.</span>size<span class="Delimiter">);</span>  <span class="Comment">// save previous size as offset</span>
      metadata<span class="Delimiter">.</span>size += size_of<span class="Delimiter">(</span>element<span class="Delimiter">.</span>type<span class="Delimiter">);</span>
    <span class="Delimiter">}</span>
    Container_metadata<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>pair&lt;type_tree*<span class="Delimiter">,</span> container_metadata&gt;<span class="Delimiter">(</span><span class="Normal">new</span> type_tree<span class="Delimiter">(</span>*type<span class="Delimiter">),</span> metadata<span class="Delimiter">));</span>
  <span class="Delimiter">}</span>
  <span class="Comment">// End compute_container_sizes Cases</span>
<span class="Delimiter">}</span>

container_metadata&amp; get<span class="Delimiter">(</span>vector&lt;pair&lt;type_tree*<span class="Delimiter">,</span> container_metadata&gt; &gt;&amp; all<span class="Delimiter">,</span> <span class="Normal">const</span> type_tree* key<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <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>all<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>matches<span class="Delimiter">(</span>all<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>first<span class="Delimiter">,</span> key<span class="Delimiter">))</span>
      <span class="Identifier">return</span> all<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>second<span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  tb_shutdown<span class="Delimiter">();</span>
  raise &lt;&lt; <span class="Constant">&quot;unknown size for type &quot;</span> &lt;&lt; to_string<span class="Delimiter">(</span>key<span class="Delimiter">)</span> &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span>
  assert<span class="Delimiter">(</span><span class="Constant">false</span><span class="Delimiter">);</span>
<span class="Delimiter">}</span>

<span class="Normal">bool</span> contains_key<span class="Delimiter">(</span><span class="Normal">const</span> vector&lt;pair&lt;type_tree*<span class="Delimiter">,</span> container_metadata&gt; &gt;&amp; all<span class="Delimiter">,</span> <span class="Normal">const</span> type_tree* key<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <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>all<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>matches<span class="Delimiter">(</span>all<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>first<span class="Delimiter">,</span> key<span class="Delimiter">))</span>
      <span class="Identifier">return</span> <span class="Constant">true</span><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="Normal">bool</span> matches<span class="Delimiter">(</span><span class="Normal">const</span> type_tree* a<span class="Delimiter">,</span> <span class="Normal">const</span> type_tree* b<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>a == b<span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">true</span><span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!a || !b<span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>a<span class="Delimiter">-&gt;</span>value != b<span class="Delimiter">-&gt;</span>value<span class="Delimiter">)</span> <span class="Identifier">return</span> <span class="Constant">false</span><span class="Delimiter">;</span>
  <span class="Identifier">return</span> matches<span class="Delimiter">(</span>a<span class="Delimiter">-&gt;</span>left<span class="Delimiter">,</span> b<span class="Delimiter">-&gt;</span>left<span class="Delimiter">)</span> &amp;&amp; matches<span class="Delimiter">(</span>a<span class="Delimiter">-&gt;</span>right<span class="Delimiter">,</span> b<span class="Delimiter">-&gt;</span>right<span class="Delimiter">);</span>
<span class="Delimiter">}</span>

<span class="Delimiter">:(scenario stash_container)</span>
def main [
  <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>  <span class="Comment"># first</span>
  <span class="Constant">2</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">36</span>
  stash [foo:]<span class="Delimiter">,</span> <span class="Constant">1</span>:point-number/<span class="Special">raw</span>
]
<span class="traceContains">+app: foo: 34 35 36</span>

<span class="SalientComment">//:: To access elements of a container, use 'get'</span>
<span class="Delimiter">:(scenario get)</span>
def main [
  <span class="Constant">12</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>
  <span class="Constant">13</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">15</span>:number<span class="Special"> &lt;- </span>get <span class="Constant">12</span>:point/<span class="Special">raw</span><span class="Delimiter">,</span> <span class="Constant">1</span>:offset  <span class="Comment"># unsafe</span>
]
<span class="traceContains">+mem: storing 35 in location 15</span>

<span class="Delimiter">:(before &quot;End Primitive Recipe Declarations&quot;)</span>
GET<span class="Delimiter">,</span>
<span class="Delimiter">:(before &quot;End Primitive Recipe Numbers&quot;)</span>
put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;get&quot;</span><span class="Delimiter">,</span> GET<span class="Delimiter">);</span>
<span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span>
<span class="Normal">case</span> GET: <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;'get' expects exactly 2 ingredients in '&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>
  reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> base = 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="Comment">// new copy for every invocation</span>
  <span class="Comment">// Update GET base in Check</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!base<span class="Delimiter">.</span>type || !base<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>value || !contains_key<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> base<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">)</span> || get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> base<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">).</span>kind != CONTAINER<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 'get' should be a container, but got '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><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>
  type_ordinal base_type = base<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">;</span>
  <span class="Normal">const</span> reagent&amp; offset = 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="Normal">if</span> <span class="Delimiter">(</span>!is_literal<span class="Delimiter">(</span>offset<span class="Delimiter">)</span> || !is_mu_scalar<span class="Delimiter">(</span>offset<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 'get' should have type 'offset', but got '&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;'</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">int</span> offset_value = <span class="Constant">0</span><span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>is_integer<span class="Delimiter">(</span>offset<span class="Delimiter">.</span>name<span class="Delimiter">))</span>  <span class="Comment">// later layers permit non-integer offsets</span>
    offset_value = to_integer<span class="Delimiter">(</span>offset<span class="Delimiter">.</span>name<span class="Delimiter">);</span>
  <span class="Normal">else</span>
    offset_value = offset<span class="Delimiter">.</span>value<span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>offset_value &lt; <span class="Constant">0</span> || offset_value &gt;= SIZE<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> base_type<span class="Delimiter">).</span>elements<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;invalid offset '&quot;</span> &lt;&lt; offset_value &lt;&lt; <span class="Constant">&quot;' for '&quot;</span> &lt;&lt; get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> base_type<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">break</span><span class="Delimiter">;</span>
  <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 GET product in Check</span>
  <span class="Normal">const</span> reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> element = element_type<span class="Delimiter">(</span>base<span class="Delimiter">.</span>type<span class="Delimiter">,</span> offset_value<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;'get &quot;</span> &lt;&lt; base<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;, &quot;</span> &lt;&lt; offset<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;' should write to &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; product<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>product<span class="Delimiter">.</span>type<span class="Delimiter">)</span> &lt;&lt; <span class="cSpecial">'\n'</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>
<span class="Delimiter">}</span>
<span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span>
<span class="Normal">case</span> GET: <span class="Delimiter">{</span>
  reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> base = current_instruction<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="Comment">// Update GET base in Run</span>
  <span class="Normal">int</span> base_address = base<span class="Delimiter">.</span>value<span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>base_address == <span class="Constant">0</span><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;tried to access location 0 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_ordinal base_type = base<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">;</span>
  <span class="Normal">int</span> offset = 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="Normal">if</span> <span class="Delimiter">(</span>offset &lt; <span class="Constant">0</span> || offset &gt;= SIZE<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> base_type<span class="Delimiter">).</span>elements<span class="Delimiter">))</span> <span class="Identifier">break</span><span class="Delimiter">;</span>  <span class="Comment">// copied from Check above</span>
  assert<span class="Delimiter">(</span>base<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>size<span class="Delimiter">);</span>
  <span class="Normal">int</span> src = base_address + base<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>offset<span class="Delimiter">.</span>at<span class="Delimiter">(</span>offset<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>
  reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> element = element_type<span class="Delimiter">(</span>base<span class="Delimiter">.</span>type<span class="Delimiter">,</span> offset<span class="Delimiter">);</span>
  element<span class="Delimiter">.</span>set_value<span class="Delimiter">(</span>src<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; names_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>
<span class="Delimiter">}</span>

<span class="Delimiter">:(code)</span>
<span class="Normal">const</span> reagent element_type<span class="Delimiter">(</span><span class="Normal">const</span> type_tree* type<span class="Delimiter">,</span> <span class="Normal">int</span> offset_value<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  assert<span class="Delimiter">(</span>offset_value &gt;= <span class="Constant">0</span><span class="Delimiter">);</span>
  assert<span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">));</span>
  assert<span class="Delimiter">(</span>!get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">).</span>name<span class="Delimiter">.</span>empty<span class="Delimiter">());</span>
  <span class="Normal">const</span> type_info&amp; info = get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">);</span>
  assert<span class="Delimiter">(</span>info<span class="Delimiter">.</span>kind == CONTAINER<span class="Delimiter">);</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>offset_value &gt;= SIZE<span class="Delimiter">(</span>info<span class="Delimiter">.</span>elements<span class="Delimiter">))</span> <span class="Identifier">return</span> reagent<span class="Delimiter">();</span>  <span class="Comment">// error handled elsewhere</span>
  reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> element = info<span class="Delimiter">.</span>elements<span class="Delimiter">.</span>at<span class="Delimiter">(</span>offset_value<span class="Delimiter">);</span>
  <span class="Comment">// End element_type Special-cases</span>
  <span class="Identifier">return</span> element<span class="Delimiter">;</span>
<span class="Delimiter">}</span>

<span class="Delimiter">:(scenario get_handles_nested_container_elements)</span>
def main [
  <span class="Constant">12</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>
  <span class="Constant">13</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">14</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">36</span>
  <span class="Constant">15</span>:number<span class="Special"> &lt;- </span>get <span class="Constant">12</span>:point-number/<span class="Special">raw</span><span class="Delimiter">,</span> <span class="Constant">1</span>:offset  <span class="Comment"># unsafe</span>
]
<span class="traceContains">+mem: storing 36 in location 15</span>

<span class="Delimiter">:(scenario get_out_of_bounds)</span>
<span class="Special">% Hide_errors = true;</span>
def main [
  <span class="Constant">12</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>
  <span class="Constant">13</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">14</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">36</span>
  get <span class="Constant">12</span>:point-number/<span class="Special">raw</span><span class="Delimiter">,</span> <span class="Constant">2</span>:offset  <span class="Comment"># point-number occupies 3 locations but has only 2 fields; out of bounds</span>
]
<span class="traceContains">+error: main: invalid offset '2' for 'point-number'</span>

<span class="Delimiter">:(scenario get_out_of_bounds_2)</span>
<span class="Special">% Hide_errors = true;</span>
def main [
  <span class="Constant">12</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>
  <span class="Constant">13</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">14</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">36</span>
  get <span class="Constant">12</span>:point-number/<span class="Special">raw</span><span class="Delimiter">,</span> -<span class="Constant">1</span>:offset
]
<span class="traceContains">+error: main: invalid offset '-1' for 'point-number'</span>

<span class="Delimiter">:(scenario get_product_type_mismatch)</span>
<span class="Special">% Hide_errors = true;</span>
def main [
  <span class="Constant">12</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>
  <span class="Constant">13</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">14</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">36</span>
  <span class="Constant">15</span>:address:number<span class="Special"> &lt;- </span>get <span class="Constant">12</span>:point-number/<span class="Special">raw</span><span class="Delimiter">,</span> <span class="Constant">1</span>:offset
]
<span class="traceContains">+error: main: 'get 12:point-number/raw, 1:offset' should write to number but '15' has type (address number)</span>

<span class="Comment">//: we might want to call 'get' without saving the results, say in a sandbox</span>

<span class="Delimiter">:(scenario get_without_product)</span>
def main [
  <span class="Constant">12</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>
  <span class="Constant">13</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  get <span class="Constant">12</span>:point/<span class="Special">raw</span><span class="Delimiter">,</span> <span class="Constant">1</span>:offset  <span class="Comment"># unsafe</span>
]
<span class="Comment"># just don't die</span>

<span class="SalientComment">//:: To write to elements of containers, use 'put'.</span>

<span class="Delimiter">:(scenario put)</span>
def main [
  <span class="Constant">12</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>
  <span class="Constant">13</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  $clear-trace
  <span class="Constant">12</span>:point<span class="Special"> &lt;- </span>put <span class="Constant">12</span>:point<span class="Delimiter">,</span> <span class="Constant">1</span>:offset<span class="Delimiter">,</span> <span class="Constant">36</span>
]
<span class="traceContains">+mem: storing 36 in location 13</span>
<span class="traceAbsent">-mem: storing 34 in location 12</span>

<span class="Delimiter">:(before &quot;End Primitive Recipe Declarations&quot;)</span>
PUT<span class="Delimiter">,</span>
<span class="Delimiter">:(before &quot;End Primitive Recipe Numbers&quot;)</span>
put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;put&quot;</span><span class="Delimiter">,</span> PUT<span class="Delimiter">);</span>
<span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span>
<span class="Normal">case</span> PUT: <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">3</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;'put' expects exactly 3 ingredients in '&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>
  reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> base = 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="Comment">// Update PUT base in Check</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!base<span class="Delimiter">.</span>type || !base<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>value || !contains_key<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> base<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">)</span> || get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> base<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">).</span>kind != CONTAINER<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 'put' should be a container, but got '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><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>
  type_ordinal base_type = base<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">;</span>
  reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> offset = 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="Comment">// Update PUT offset in Check</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!is_literal<span class="Delimiter">(</span>offset<span class="Delimiter">)</span> || !is_mu_scalar<span class="Delimiter">(</span>offset<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 'put' should have type 'offset', but got '&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;'</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">int</span> offset_value = <span class="Constant">0</span><span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>is_integer<span class="Delimiter">(</span>offset<span class="Delimiter">.</span>name<span class="Delimiter">))</span> <span class="Delimiter">{</span>  <span class="Comment">// later layers permit non-integer offsets</span>
    offset_value = to_integer<span class="Delimiter">(</span>offset<span class="Delimiter">.</span>name<span class="Delimiter">);</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>offset_value &lt; <span class="Constant">0</span> || offset_value &gt;= SIZE<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> base_type<span class="Delimiter">).</span>elements<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;invalid offset '&quot;</span> &lt;&lt; offset_value &lt;&lt; <span class="Constant">&quot;' for '&quot;</span> &lt;&lt; get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> base_type<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">break</span><span class="Delimiter">;</span>
    <span class="Delimiter">}</span>
  <span class="Delimiter">}</span>
  <span class="Normal">else</span> <span class="Delimiter">{</span>
    offset_value = offset<span class="Delimiter">.</span>value<span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  <span class="Normal">const</span> reagent&amp; 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="Normal">const</span> reagent&amp; element = element_type<span class="Delimiter">(</span>base<span class="Delimiter">.</span>type<span class="Delimiter">,</span> offset_value<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 &quot;</span> &lt;&lt; base<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;, &quot;</span> &lt;&lt; offset<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;' should write to &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>
    <span class="Identifier">break</span><span class="Delimiter">;</span>
  <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>  <span class="Comment">// no more checks necessary</span>
  <span class="Normal">if</span> <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>name != inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>name<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;product of 'put' must be first ingredient '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>original_string &lt;&lt; <span class="Constant">&quot;', but got '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><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="Comment">// End PUT Product Checks</span>
  <span class="Identifier">break</span><span class="Delimiter">;</span>
<span class="Delimiter">}</span>
<span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span>
<span class="Normal">case</span> PUT: <span class="Delimiter">{</span>
  reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> base = current_instruction<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="Comment">// Update PUT base in Run</span>
  <span class="Normal">int</span> base_address = base<span class="Delimiter">.</span>value<span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>base_address == <span class="Constant">0</span><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;tried to access location 0 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_ordinal base_type = base<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">;</span>
  <span class="Normal">int</span> offset = 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="Normal">if</span> <span class="Delimiter">(</span>offset &lt; <span class="Constant">0</span> || offset &gt;= SIZE<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> base_type<span class="Delimiter">).</span>elements<span class="Delimiter">))</span> <span class="Identifier">break</span><span class="Delimiter">;</span>  <span class="Comment">// copied from Check above</span>
  <span class="Normal">int</span> address = base_address + base<span class="Delimiter">.</span>metadata<span class="Delimiter">.</span>offset<span class="Delimiter">.</span>at<span class="Delimiter">(</span>offset<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 container</span>
  <span class="Comment">// Write Memory in PUT in Run</span>
  <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>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">2</span><span class="Delimiter">));</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">&quot;mem&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;storing &quot;</span> &lt;&lt; no_scientific<span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">2</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span>i<span class="Delimiter">))</span> &lt;&lt; <span class="Constant">&quot; in location &quot;</span> &lt;&lt; address+i &lt;&lt; end<span class="Delimiter">();</span>
    put<span class="Delimiter">(</span>Memory<span class="Delimiter">,</span> address+i<span class="Delimiter">,</span> ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">2</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span>i<span class="Delimiter">));</span>
  <span class="Delimiter">}</span>
  <span class="Identifier">goto</span> finish_instruction<span class="Delimiter">;</span>
<span class="Delimiter">}</span>

<span class="Delimiter">:(scenario put_product_error)</span>
<span class="Special">% Hide_errors = true;</span>
def main [
  local-scope
  load-ingredients
  <span class="Constant">1</span>:point<span class="Special"> &lt;- </span>merge <span class="Constant">34</span><span class="Delimiter">,</span> <span class="Constant">35</span>
  <span class="Constant">3</span>:point<span class="Special"> &lt;- </span>put <span class="Constant">1</span>:point<span class="Delimiter">,</span> x:offset<span class="Delimiter">,</span> <span class="Constant">36</span>
]
<span class="traceContains">+error: main: product of 'put' must be first ingredient '1:point', but got '3:point'</span>

<span class="SalientComment">//:: Allow containers to be defined in mu code.</span>

<span class="Delimiter">:(scenarios load)</span>
<span class="Delimiter">:(scenario container)</span>
container foo [
  <span class="Normal">x</span>:number
  <span class="Normal">y</span>:number
]
<span class="traceContains">+parse: --- defining container foo</span>
<span class="traceContains">+parse: element: {x: &quot;number&quot;}</span>
<span class="traceContains">+parse: element: {y: &quot;number&quot;}</span>

<span class="Delimiter">:(scenario container_use_before_definition)</span>
container foo [
  <span class="Normal">x</span>:number
  <span class="Normal">y</span>:bar
]
container bar [
  <span class="Normal">x</span>:number
  <span class="Normal">y</span>:number
]
<span class="traceContains">+parse: --- defining container foo</span>
<span class="traceContains">+parse: type number: 1000</span>
<span class="traceContains">+parse:   element: {x: &quot;number&quot;}</span>
<span class="Comment"># todo: brittle</span>
<span class="Comment"># type bar is unknown at this point, but we assign it a number</span>
<span class="traceContains">+parse:   element: {y: &quot;bar&quot;}</span>
<span class="Comment"># later type bar geon</span>
<span class="traceContains">+parse: --- defining container bar</span>
<span class="traceContains">+parse: type number: 1001</span>
<span class="traceContains">+parse:   element: {x: &quot;number&quot;}</span>
<span class="traceContains">+parse:   element: {y: &quot;number&quot;}</span>

<span class="Comment">//: if a container is defined again, the new fields add to the original definition</span>
<span class="Delimiter">:(scenarios run)</span>
<span class="Delimiter">:(scenario container_extend)</span>
container foo [
  <span class="Normal">x</span>:number
]
<span class="Comment"># add to previous definition</span>
container foo [
  <span class="Normal">y</span>:number
]
def main [
  <span class="Constant">1</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">34</span>
  <span class="Constant">2</span>:number<span class="Special"> &lt;- </span>copy <span class="Constant">35</span>
  <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>get <span class="Constant">1</span>:foo<span class="Delimiter">,</span> <span class="Constant">0</span>:offset
  <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>get <span class="Constant">1</span>:foo<span class="Delimiter">,</span> <span class="Constant">1</span>:offset
]
<span class="traceContains">+mem: storing 34 in location 3</span>
<span class="traceContains">+mem: storing 35 in location 4</span>

<span class="Delimiter">:(before &quot;End Command Handlers&quot;)</span>
<span class="Normal">else</span> <span class="Normal">if</span> <span class="Delimiter">(</span>command == <span class="Constant">&quot;container&quot;</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
  insert_container<span class="Delimiter">(</span>command<span class="Delimiter">,</span> CONTAINER<span class="Delimiter">,</span> in<span class="Delimiter">);</span>
<span class="Delimiter">}</span>

<span class="Comment">//: Even though we allow containers to be extended, we don't allow this after</span>
<span class="Comment">//: a call to transform_all. But we do want to detect this situation and raise</span>
<span class="Comment">//: an error. This field will help us raise such errors.</span>
<span class="Delimiter">:(before &quot;End type_info Fields&quot;)</span>
<span class="Normal">int</span> Num_calls_to_transform_all_at_first_definition<span class="Delimiter">;</span>
<span class="Delimiter">:(before &quot;End type_info Constructor&quot;)</span>
Num_calls_to_transform_all_at_first_definition = -<span class="Constant">1</span><span class="Delimiter">;</span>

<span class="Delimiter">:(code)</span>
<span class="Normal">void</span> insert_container<span class="Delimiter">(</span><span class="Normal">const</span> string&amp; command<span class="Delimiter">,</span> kind_of_type kind<span class="Delimiter">,</span> istream&amp; in<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  skip_whitespace_but_not_newline<span class="Delimiter">(</span>in<span class="Delimiter">);</span>
  string name = next_word<span class="Delimiter">(</span>in<span class="Delimiter">);</span>
  <span class="Comment">// End container Name Refinements</span>
  trace<span class="Delimiter">(</span><span class="Constant">9991</span><span class="Delimiter">,</span> <span class="Constant">&quot;parse&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;--- defining &quot;</span> &lt;&lt; command &lt;&lt; <span class="Constant">' '</span> &lt;&lt; name &lt;&lt; end<span class="Delimiter">();</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> name<span class="Delimiter">)</span>
      || get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> name<span class="Delimiter">)</span> == <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
    put<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> name<span class="Delimiter">,</span> Next_type_ordinal++<span class="Delimiter">);</span>
  <span class="Delimiter">}</span>
  trace<span class="Delimiter">(</span><span class="Constant">9999</span><span class="Delimiter">,</span> <span class="Constant">&quot;parse&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;type number: &quot;</span> &lt;&lt; get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> name<span class="Delimiter">)</span> &lt;&lt; end<span class="Delimiter">();</span>
  skip_bracket<span class="Delimiter">(</span>in<span class="Delimiter">,</span> <span class="Constant">&quot;'&quot;</span>+command+<span class="Constant">&quot;' must begin with '['&quot;</span><span class="Delimiter">);</span>
  type_info&amp; info = get_or_insert<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> name<span class="Delimiter">));</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>info<span class="Delimiter">.</span>Num_calls_to_transform_all_at_first_definition == -<span class="Constant">1</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Comment">// initial definition of this container</span>
    info<span class="Delimiter">.</span>Num_calls_to_transform_all_at_first_definition = Num_calls_to_transform_all<span class="Delimiter">;</span>
  <span class="Delimiter">}</span>
  <span class="Normal">else</span> <span class="Normal">if</span> <span class="Delimiter">(</span>info<span class="Delimiter">.</span>Num_calls_to_transform_all_at_first_definition != Num_calls_to_transform_all<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Comment">// extension after transform_all</span>
    raise &lt;&lt; <span class="Constant">&quot;there was a call to transform_all() between the definition of container '&quot;</span> &lt;&lt; name &lt;&lt; <span class="Constant">&quot;' and a subsequent extension. This is not supported, since any recipes that used '&quot;</span> &lt;&lt; name &lt;&lt; <span class="Constant">&quot;' values have already been transformed and </span><span class="cSpecial">\&quot;</span><span class="Constant">frozen</span><span class="cSpecial">\&quot;</span><span class="Constant">.</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="Delimiter">;</span>
  <span class="Delimiter">}</span>
  info<span class="Delimiter">.</span>name = name<span class="Delimiter">;</span>
  info<span class="Delimiter">.</span>kind = kind<span class="Delimiter">;</span>
  <span class="Normal">while</span> <span class="Delimiter">(</span>has_data<span class="Delimiter">(</span>in<span class="Delimiter">))</span> <span class="Delimiter">{</span>
    skip_whitespace_and_comments<span class="Delimiter">(</span>in<span class="Delimiter">);</span>
    string element = next_word<span class="Delimiter">(</span>in<span class="Delimiter">);</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>element == <span class="Constant">&quot;]&quot;</span><span class="Delimiter">)</span> <span class="Identifier">break</span><span class="Delimiter">;</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>in<span class="Delimiter">.</span>peek<span class="Delimiter">()</span> != <span class="cSpecial">'\n'</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>
      raise &lt;&lt; command &lt;&lt; <span class="Constant">&quot; '&quot;</span> &lt;&lt; name &lt;&lt; <span class="Constant">&quot;' contains multiple elements on a single line. Containers and exclusive containers must only contain elements, one to a line, no code.</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span>
      <span class="Comment">// skip rest of container declaration</span>
      <span class="Normal">while</span> <span class="Delimiter">(</span>has_data<span class="Delimiter">(</span>in<span class="Delimiter">))</span> <span class="Delimiter">{</span>
        skip_whitespace_and_comments<span class="Delimiter">(</span>in<span class="Delimiter">);</span>
        <span class="Normal">if</span> <span class="Delimiter">(</span>next_word<span class="Delimiter">(</span>in<span class="Delimiter">)</span> == <span class="Constant">&quot;]&quot;</span><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>
    <span class="Delimiter">}</span>
    info<span class="Delimiter">.</span>elements<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>reagent<span class="Delimiter">(</span>element<span class="Delimiter">));</span>
    replace_unknown_types_with_unique_ordinals<span class="Delimiter">(</span>info<span class="Delimiter">.</span>elements<span class="Delimiter">.</span>back<span class="Delimiter">().</span>type<span class="Delimiter">,</span> info<span class="Delimiter">);</span>
    trace<span class="Delimiter">(</span><span class="Constant">9993</span><span class="Delimiter">,</span> <span class="Constant">&quot;parse&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;  element: &quot;</span> &lt;&lt; to_string<span class="Delimiter">(</span>info<span class="Delimiter">.</span>elements<span class="Delimiter">.</span>back<span class="Delimiter">())</span> &lt;&lt; end<span class="Delimiter">();</span>
    <span class="Comment">// End Load Container Element Definition</span>
  <span class="Delimiter">}</span>
<span class="Delimiter">}</span>

<span class="Normal">void</span> replace_unknown_types_with_unique_ordinals<span class="Delimiter">(</span>type_tree* type<span class="Delimiter">,</span> <span class="Normal">const</span> type_info&amp; info<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!type<span class="Delimiter">)</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!type<span class="Delimiter">-&gt;</span>name<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Delimiter">{</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>name<span class="Delimiter">))</span> <span class="Delimiter">{</span>
      type<span class="Delimiter">-&gt;</span>value = get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>name<span class="Delimiter">);</span>
    <span class="Delimiter">}</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="Comment">// End insert_container Special-cases</span>
    <span class="Normal">else</span> <span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>name != <span class="Constant">&quot;-&gt;&quot;</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>  <span class="Comment">// used in recipe types</span>
      put<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>name<span class="Delimiter">,</span> Next_type_ordinal++<span class="Delimiter">);</span>
      type<span class="Delimiter">-&gt;</span>value = get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>name<span class="Delimiter">);</span>
    <span class="Delimiter">}</span>
  <span class="Delimiter">}</span>
  replace_unknown_types_with_unique_ordinals<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>left<span class="Delimiter">,</span> info<span class="Delimiter">);</span>
  replace_unknown_types_with_unique_ordinals<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">,</span> info<span class="Delimiter">);</span>
<span class="Delimiter">}</span>

<span class="Normal">void</span> skip_bracket<span class="Delimiter">(</span>istream&amp; in<span class="Delimiter">,</span> string message<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  skip_whitespace_and_comments<span class="Delimiter">(</span>in<span class="Delimiter">);</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>in<span class="Delimiter">.</span>get<span class="Delimiter">()</span> != <span class="Constant">'['</span><span class="Delimiter">)</span>
    raise &lt;&lt; message &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span>
<span class="Delimiter">}</span>

<span class="Delimiter">:(scenario multi_word_line_in_container_declaration)</span>
<span class="Special">% Hide_errors = true;</span>
container foo [
  <span class="Normal">x</span>:number y:number
]
<span class="traceContains">+error: container 'foo' contains multiple elements on a single line. Containers and exclusive containers must only contain elements, one to a line, no code.</span>

<span class="Comment">//: ensure scenarios are consistent by always starting them at the same type</span>
<span class="Comment">//: number.</span>
<span class="Delimiter">:(before &quot;End Setup&quot;)</span>  <span class="Comment">//: for tests</span>
Next_type_ordinal = <span class="Constant">1000</span><span class="Delimiter">;</span>
<span class="Delimiter">:(before &quot;End Test Run Initialization&quot;)</span>
assert<span class="Delimiter">(</span>Next_type_ordinal &lt; <span class="Constant">1000</span><span class="Delimiter">);</span>

<span class="Delimiter">:(code)</span>
<span class="Normal">void</span> test_error_on_transform_all_between_container_definition_and_extension<span class="Delimiter">()</span> <span class="Delimiter">{</span>
  <span class="Comment">// define a container</span>
  run<span class="Delimiter">(</span><span class="Constant">&quot;container foo [</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span>
      <span class="Constant">&quot;  a:number</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span>
      <span class="Constant">&quot;]</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">);</span>
  <span class="Comment">// try to extend the container after transform</span>
  transform_all<span class="Delimiter">();</span>
  CHECK_TRACE_DOESNT_CONTAIN_ERROR<span class="Delimiter">();</span>
  Hide_errors = <span class="Constant">true</span><span class="Delimiter">;</span>
  run<span class="Delimiter">(</span><span class="Constant">&quot;container foo [</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span>
      <span class="Constant">&quot;  b:number</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span>
      <span class="Constant">&quot;]</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span><span class="Delimiter">);</span>
  CHECK_TRACE_CONTAINS_ERROR<span class="Delimiter">();</span>
<span class="Delimiter">}</span>

<span class="SalientComment">//:: Allow container definitions anywhere in the codebase, but complain if you</span>
<span class="SalientComment">//:: can't find a definition at the end.</span>

<span class="Delimiter">:(scenario run_complains_on_unknown_types)</span>
<span class="Special">% Hide_errors = true;</span>
def main [
  <span class="Comment"># integer is not a type</span>
  <span class="Constant">1</span>:integer<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
]
<span class="traceContains">+error: main: unknown type integer in '1:integer &lt;- copy 0'</span>

<span class="Delimiter">:(scenario run_allows_type_definition_after_use)</span>
def main [
  <span class="Constant">1</span>:bar<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>/unsafe
]
container bar [
  <span class="Normal">x</span>:number
]
$error: <span class="Constant">0</span>

<span class="Delimiter">:(after &quot;Begin Instruction Modifying Transforms&quot;)</span>
<span class="Comment">// Begin Type Modifying Transforms</span>
Transform<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>check_or_set_invalid_types<span class="Delimiter">);</span>  <span class="Comment">// idempotent</span>
<span class="Comment">// End Type Modifying Transforms</span>

<span class="Delimiter">:(code)</span>
<span class="Normal">void</span> check_or_set_invalid_types<span class="Delimiter">(</span><span class="Normal">const</span> recipe_ordinal r<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  recipe&amp; caller = get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">);</span>
  trace<span class="Delimiter">(</span><span class="Constant">9991</span><span class="Delimiter">,</span> <span class="Constant">&quot;transform&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;--- check for invalid types in recipe &quot;</span> &lt;&lt; caller<span class="Delimiter">.</span>name &lt;&lt; end<span class="Delimiter">();</span>
  <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> index = <span class="Constant">0</span><span class="Delimiter">;</span> index &lt; SIZE<span class="Delimiter">(</span>caller<span class="Delimiter">.</span>steps<span class="Delimiter">);</span> ++index<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    instruction&amp; inst = caller<span class="Delimiter">.</span>steps<span class="Delimiter">.</span>at<span class="Delimiter">(</span>index<span class="Delimiter">);</span>
    <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>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span>
      check_or_set_invalid_types<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>type<span class="Delimiter">,</span> maybe<span class="Delimiter">(</span>caller<span class="Delimiter">.</span>name<span class="Delimiter">),</span> <span class="Constant">&quot;'&quot;</span>+inst<span class="Delimiter">.</span>original_string+<span class="Constant">&quot;'&quot;</span><span class="Delimiter">);</span>
    <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>inst<span class="Delimiter">.</span>products<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span>
      check_or_set_invalid_types<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>type<span class="Delimiter">,</span> maybe<span class="Delimiter">(</span>caller<span class="Delimiter">.</span>name<span class="Delimiter">),</span> <span class="Constant">&quot;'&quot;</span>+inst<span class="Delimiter">.</span>original_string+<span class="Constant">&quot;'&quot;</span><span class="Delimiter">);</span>
  <span class="Delimiter">}</span>
  <span class="Comment">// End check_or_set_invalid_types</span>
<span class="Delimiter">}</span>

<span class="Normal">void</span> check_or_set_invalid_types<span class="Delimiter">(</span>type_tree* type<span class="Delimiter">,</span> <span class="Normal">const</span> string&amp; block<span class="Delimiter">,</span> <span class="Normal">const</span> string&amp; name<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!type<span class="Delimiter">)</span> <span class="Identifier">return</span><span class="Delimiter">;</span>  <span class="Comment">// will throw a more precise error elsewhere</span>
  <span class="Comment">// End Container Type Checks</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>value == <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Identifier">return</span><span class="Delimiter">;</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">))</span> <span class="Delimiter">{</span>
    assert<span class="Delimiter">(</span>!type<span class="Delimiter">-&gt;</span>name<span class="Delimiter">.</span>empty<span class="Delimiter">());</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>contains_key<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>name<span class="Delimiter">))</span>
      type<span class="Delimiter">-&gt;</span>value = get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>name<span class="Delimiter">);</span>
    <span class="Normal">else</span>
      raise &lt;&lt; block &lt;&lt; <span class="Constant">&quot;unknown type &quot;</span> &lt;&lt; type<span class="Delimiter">-&gt;</span>name &lt;&lt; <span class="Constant">&quot; in &quot;</span> &lt;&lt; name &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span>
  <span class="Delimiter">}</span>
  check_or_set_invalid_types<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>left<span class="Delimiter">,</span> block<span class="Delimiter">,</span> name<span class="Delimiter">);</span>
  check_or_set_invalid_types<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">,</span> block<span class="Delimiter">,</span> name<span class="Delimiter">);</span>
<span class="Delimiter">}</span>

<span class="Delimiter">:(scenario container_unknown_field)</span>
<span class="Special">% Hide_errors = true;</span>
container foo [
  <span class="Normal">x</span>:number
  <span class="Normal">y</span>:bar
]
<span class="traceContains">+error: foo: unknown type in y</span>

<span class="Delimiter">:(scenario read_container_with_bracket_in_comment)</span>
container foo [
  <span class="Normal">x</span>:number
  <span class="Comment"># ']' in comment</span>
  <span class="Normal">y</span>:number
]
<span class="traceContains">+parse: --- defining container foo</span>
<span class="traceContains">+parse: element: {x: &quot;number&quot;}</span>
<span class="traceContains">+parse: element: {y: &quot;number&quot;}</span>

<span class="Delimiter">:(scenario container_with_compound_field_type)</span>
container foo [
  <span class="Delimiter">{</span>x: <span class="Delimiter">(</span>address array <span class="Delimiter">(</span>address array character<span class="Delimiter">))}</span>
]
$error: <span class="Constant">0</span>

<span class="Delimiter">:(before &quot;End transform_all&quot;)</span>
check_container_field_types<span class="Delimiter">();</span>

<span class="Delimiter">:(code)</span>
<span class="Normal">void</span> check_container_field_types<span class="Delimiter">()</span> <span class="Delimiter">{</span>
  <span class="Normal">for</span> <span class="Delimiter">(</span>map&lt;type_ordinal<span class="Delimiter">,</span> type_info&gt;::iterator p = Type<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != Type<span class="Delimiter">.</span>end<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> <span class="Delimiter">{</span>
    <span class="Normal">const</span> type_info&amp; info = p<span class="Delimiter">-&gt;</span>second<span class="Delimiter">;</span>
    <span class="Comment">// Check Container Field Types(info)</span>
    <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>info<span class="Delimiter">.</span>elements<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span>
      check_invalid_types<span class="Delimiter">(</span>info<span class="Delimiter">.</span>elements<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>type<span class="Delimiter">,</span> maybe<span class="Delimiter">(</span>info<span class="Delimiter">.</span>name<span class="Delimiter">),</span> info<span class="Delimiter">.</span>elements<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">).</span>name<span class="Delimiter">);</span>
  <span class="Delimiter">}</span>
<span class="Delimiter">}</span>

<span class="Normal">void</span> check_invalid_types<span class="Delimiter">(</span><span class="Normal">const</span> type_tree* type<span class="Delimiter">,</span> <span class="Normal">const</span> string&amp; block<span class="Delimiter">,</span> <span class="Normal">const</span> string&amp; name<span class="Delimiter">)</span> <span class="Delimiter">{</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>!type<span class="Delimiter">)</span> <span class="Identifier">return</span><span class="Delimiter">;</span>  <span class="Comment">// will throw a more precise error elsewhere</span>
  <span class="Normal">if</span> <span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>value != <span class="Constant">0</span><span class="Delimiter">)</span> <span class="Delimiter">{</span>  <span class="Comment">// value 0 = compound types (layer parse_tree) or type ingredients (layer shape_shifting_container)</span>
    <span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span>Type<span class="Delimiter">,</span> type<span class="Delimiter">-&gt;</span>value<span class="Delimiter">))</span>
      raise &lt;&lt; block &lt;&lt; <span class="Constant">&quot;unknown type in &quot;</span> &lt;&lt; name &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span>
  <span class="Delimiter">}</span>
  check_invalid_types<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>left<span class="Delimiter">,</span> block<span class="Delimiter">,</span> name<span class="Delimiter">);</span>
  check_invalid_types<span class="Delimiter">(</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">,</span> block<span class="Delimiter">,</span> name<span class="Delimiter">);</span>
<span class="Delimiter">}</span>
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->